I would like to have a form available on every page in my web app. So I created a widget with a form.
class AddNewURL extends Widget{
public $model;
public function init()
{
parent::init();
if ($this->model === null) {
$this->model = new ProductUrlForm();
}
}
public function run()
{
return $this->render('addNewURLForm', [
'model' => $this->model,
]);
}
}
and widget view
<div class="modal fade bs-example-modal-lg" id="newURL" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<?php Pjax::begin(); ?>
<?php $form = ActiveForm::begin([
'action' => Url::to(['site/new-url']),
'options' => ['data' => ['pjax' => true]],
]) ?>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">Add new URL</h4>
</div>
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<?= $form->field($model, 'url', ['errorOptions' => ['class' => 'help-block', 'encode' => false]])
->textInput(['maxlength' => false])
?>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Add</button>
</div>
<?php ActiveForm::end() ?>
<?php Pjax::end(); ?>
</div>
</div>
</div>
and this how I use this widget in my layouts/main.php
<?= \app\widgets\AddNewURL::widget() ?>
in my site/new-url action I have
public function actionNewUrl()
{
$model = new ProductUrlForm();
$model->status = STATUS_NEW;
if ($model->load(Yii::$app->request->post()) && $model->save()) {
//return success message
}
return $this->render('index', [
'model' => $model,
]);
}
and now when I submit form data goes to my action, the form is reset and that's all. How to show validation error or success message using pjax? In my model I have few custom validation rules.
Maybe there is better solution to use one form on all pages?
Action actionNewUrl() must render view addNewURLForm so Pjax can replace old form with new html recieved from the action.
It is better to place your widget, controller and form model to separate module.
Related
I'm trying to render an edit form in a modal for each element on the same page I create them, but it seems not possible to render a same form multiple times.
This is my controller:
/**
* #Route("/outcome", name="outcome")
*/
public function index(OutcomeRepository $repo, Request $request, EntityManagerInterface $manager): Response
{
$outcomes = $repo->findAll();
$outcome = new Outcome();
$form = $this->createForm(OutcomeType::class, $outcome);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$manager->persist($outcome);
$manager->flush();
$this->addFlash(
'success',
"Income <strong>{$outcome->getTitle()}</strong> has been added."
);
return $this->redirectToRoute('outcome');
}
return $this->render('outcome/outcome.html.twig', [
'outcomes' => $outcomes,
'form' => $form->createView(),
]);
}
This is the OutcomeType:
class OutcomeType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, [
'label' => "Title",
'attr' => [
'placeholder' => "Write a title"
]
])
->add('amount', MoneyType::class, [
'label' => "Amount",
'attr' => [
'placeholder' => "Write an amount"
]
])
->add('save', SubmitType::class, [
'label' => 'Send',
'attr' => [
'class' => 'btn btn-primary'
]
]);
}
And this is the twig part:
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#newOutcomeModal">
New outcome
</button>
<div class="modal fade" id="newOutcomeModal" tabindex="-1" aria-labelledby="newOutcomeModal" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="newOutcomeModal">Add a new outcome</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{{form_start(form)}}
{{form_widget(form)}}
{{form_end(form)}}
</div>
</div>
</div>
</div>
{% for outcome in outcomes %}
<div class="card m-4">
<div class="card-body">
<h5 class="card-title">{{outcome.title}}</h5>
<p class="card-text">{{outcome.amount}}</p>
<button type="button" class="btn btn-secondary" data-bs-toggle="modal" data-bs-target="#editOutcomeModal{{outcome.id}}">Edit</button>
</div>
</div>
<div class="modal fade" id="editOutcomeModal{{outcome.id}}" tabindex="-1" aria-labelledby="editOutcomeModal{{outcome.id}}" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="editOutcomeModal{{outcome.id}}">Edit {{outcome.title}} outcome</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
{{form_start(form)}}
{{form_widget(form)}}
{{form_end(form)}}
</div>
</div>
</div>
</div>
{% endfor %}
I get the error: "An exception has been thrown during the rendering of a template ("Field "outcome" has already been rendered, save the result of previous render call to a variable and output that instead.")."
I don't know how to solve this. I tried to turn the fields of OutcomeType in a collectionType but it didn't work.
Can someone help me please ?
I am creating a form with Zend Framework 2. I'm using Form class to define form elements like this:
class PropertyForm extends Form
{
public function __construct($name=null)
{
...
$this->add(array(
'name' => 'zip',
'type' => 'Text',
'required' => false,
'options' => array(
'label' => 'Zip Code',
),
'attributes' => array(
'id' => 'zip',
'class' => 'form-control',
),
));
...
}
}
And in view I display this form element with the following code:
<div class="form-group"><?php echo $this->formRow($form->get('zip')); ?></div>
This generates the following HTML output:
<div class="form-group">
<label for="zip">Zip Code</label>
<input type="text" name="zip" id="zip" class="form-control" value="">
</div>
What I want to achieve is to have <div class="my-class"> around the input field as well. So the desired HTML output would be:
<div class="form-group">
<label for="zip">Zip Code</label>
<div class="my-class">
<input type="text" name="zip" id="zip" class="form-control" value="">
</div>
</div>
How can I achieve that?
You could get label and the element itself with two different calls:
For label:
<?php echo $this->formLabel($yourForm->get('your_element')); ?>
For the elements:
<?php echo $this->formSelect($yourForm->get('your_element_select')); ?>
<?php echo $this->formText($yourForm->get('your_element_text')); ?>
<?php echo $this->formRadio($yourForm->get('your_element_radio')); ?>
So, for you example, it would be something like:
<div class="form-group">
<?php echo $this->formLabel($form->get('zip')); ?>
<div class="my-class">
<?php echo $this->formText($form->get('zip')); ?>
</div>
</div>
I have created a REST API for inserting data from Modal. After submitting my form I get data from my "store" controller. But when I call a Model function to insert that data to Database then I am getting 500 internal server error at console.
I have tried with two ways 1. Using Eloquent ORM
2. Using Query Builder
My controller:
public function store(Request $request)
{
$category_name = $request->category_name;
$category_entry_date = $request->category_entry_date;
$category_info = array(
'Supplier_Name' => $category_name,
'Supplier_Des' => $category_entry_date,
'Shop_Id' => 1
);
// Insert data into database
Product::CreateProductCategory($category_info);
return response()->json(['success_massege'=>'Category Added Successfully']);
}
Js:
$("#category_submit").click(function (e) {
event.preventDefault();
var category_name = $('#category_name_id').val();
var category_entry_date = $('#category_entry_date_id').val();
if (category_name && category_entry_date) {
$.post("/api/api/product_category", {category_name: category_name, category_entry_date: category_entry_date}).done(function (data) {
$('#category_name_id').val("");
$('#category_entry_date_id').val("");
var success_massege_dialogbox = '';
success_massege_dialogbox += '<div class="alert alert-success fade in">';
success_massege_dialogbox += '×';
success_massege_dialogbox += '<strong>Success!</strong>' + data.success_massege + '</div>';
$('#success_massege').append(success_massege_dialogbox);
});
}
else {
alert('Please give a category name and entry date');
}
});
Model:
static function CreateProductCategory($category_info){
DB::table('product_category_info')->insert($category_info);
}
View:
<div class="modal fade" id="addCategory" tabindex="-1" role="dialog" aria-labelledby="addCategoryLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="addCategoryLabel">Add Category</h4>
</div>
<form action="{{ route('product_category.store') }}" method="POST">
<div class="modal-body">
<div class="modal-body">
<div class="box-body">
<div class="row form-group">
<div class="col-md-3 form-level"></div>
<div class="col-md-9" id="success_massege"> </div>
</div>
<div class="row form-group">
<div class="col-md-3 form-level"><label>Category Name<b class="mandetory_star">*</b></label></div>
<div class="col-md-9" id="email-error-dialog">
{{Form::text('category_name','', $attributes = array('class' => 'form-control',
'id' => 'category_name_id',
'data-validation'=>'alphanumeric', 'data-validation-allowing'=>'-_',
'data-validation-error-msg'=>'Please Enter a Valid Category Name',
'data-validation-error-msg-container'=>'#email-error-dialog',
))}}
</div>
</div>
<div class="row form-group">
<div class="col-md-3 form-level"><label>Entry Date<b class="mandetory_star">*</b></label></div>
<div class="col-md-9" id="date-error-dialog">
{{Form::date('entry_date','', $attributes = array('class' => 'form-control',
'id' => 'category_entry_date_id',
'data-validation'=>'date',
'data-validation-error-msg'=>'Please Enter a Valid Date',
'data-validation-error-msg-container'=>'#date-error-dialog'))}}
</div>
</div>
</div><!-- /.box-body -->
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button id="category_submit" type="submit" class="btn btn-primary save-category"> Save category </button>
</div>
</form>
</div>
</div>
</div>
I've made a login form and now I need to have the same code in one of my Cakephp project but it doesn't work..
<!-- LOGIN SECTION START -->
<section id="login">
<div class="container">
<div class="row">
<div class="Absolute-Center is-Responsive">
<h1 class="text-center form-login-title">Log In</h1>
<div class="col-sm-12 col-md-12 col-md-offset-0">
<?php echo $this->Session->flash('auth'); ?>
<?php echo $this->Form->create('User');?>
<div class="form-group inner-icon right-icon"> <!--USER NAME-->
<i class="glyphicon glyphicon-user"></i>
<input class="form-control" type="text" name='username' placeholder="username"/>
</div>
<div class="form-group inner-icon right-icon"> <!--PASSWORD-->
<i class="glyphicon glyphicon-lock"></i>
<input class="form-control" type="password" name='password' placeholder="password"/>
</div>
<?= $this->Form->end(__('Sign In')); ?> <!-- SUBMIT BUTTON -->
<div class="form-group text-center">
Forgot Password
</div>
</div><!-- /.col-sm-12 -->
</div>
</div><!-- /.row -->
</div><!-- /.container -->
</section>
<!-- LOGIN SECTION END -->
So with that snippet does not let me log in (the back end is not the problem)
Oh, and how can I change the submit button style ? I've tried <?= $this->Form->end(__(Sign In), array('class'=>'btn-primary')); ?>
but it doesn't help much :(
Thanks
You should use the CakePHP helpers, so instead plain HTML:
Change this:
<input class="form-control" type="text" name='username' placeholder="username"/>
Into this:
<?php
echo $this->Form->input('username', array(
'class' => 'form-control',
'placeholder' => 'username',
'label' => false
));
?>
And this:
<input class="form-control" type="password" name='password' placeholder="password"/>
Into this:
<?php
echo $this->Form->input('password', array(
'type' => 'password',
'class' => 'form-control',
'placeholder' => 'password',
'label' => false
)); ?>
CakePHP Helper will print the input fields with the correct name values for each one, so in your controller you receive the correct data through the array $this->request->data.
For the button style try:
<?=$this->Form->end('Sign In', array('class'=>'btn btn-danger'))?>
Like Ricardo mentioned,use CakePHP syntax and conventions.
Also it will be more helpful if you provide your controller actions. Probably your action is wrong.
For more things about forms and auth here:
http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
*I speak English not well. So i'm going to post the code now.*
Form code:
protected $elementDecorators = array('ViewHelper','Errors','Description','Label',
array('HtmlTag',array('tag' => 'div','class' => '_wrapperElement')
));
public function init(){
$this->addElement('text','mytext',array(
'class' => '_inputText',
'label' => 'Mytext',
'required' => true,
'decorators' => $this->elementDecorators
));
$this->setDecorators(array('FormElements',array('HtmlTag',array('tag' => 'div','class' => '_formWrapper')),'Form'));
}
Output:
<form method="post" action="" enctype="application/x-www-form-urlencoded">
<div class="_formWrapper">
<div class="_wrapperElement">
<label class="required" for="mytext">Mytext</label>
<input type="text" class="_inputText" value="" id="mytext" name="mytext">
</div>
</div>
</form>
Now i want a div wraps Label and Input element like this:
<form method="post" action="" enctype="application/x-www-form-urlencoded">
<div class="_formWrapper">
<div class="_wrapperElement">
<div class="_wrapperLabel">
<label class="required" for="mytext">Mytext</label>
</div>
<div class="_wrapperInput">
<input type="text" class="_inputText" value="" id="mytext" name="mytext">
</div>
</div>
</div>
</form>
How to do that?
I tried many times but i can't do it.
Thanks!
protected $elementDecorators = array('ViewHelper','Errors','Description', array('Label', array('tag' => 'div', 'class' => '_wrapperLabel')
),
array('HtmlTag',array('tag' => 'div','class' => '_wrapperInput')
));
i found the solution that render decorators to ViewScript.