Symfony 3 form + Aurelia - aurelia

So i've playing around with building a web app in Symfony 3, using a form type and rendering the form on the page. I am starting to Aurelia, and am trying to render a Symfony form on the page via an Aurelia custom element, and then post the form back to symfony. I've gotten to the point of validating the form upon submit, but it never validates. Can someone please look over the below code and see if i'm missing something somewhere?
Form type:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use AppBundle\Service\PayeeService;
class PayeeType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', TextType::class)
->add('category', ChoiceType::class, [
'choices' => [
'Uncategorized' => PayeeService::CATEGORY_UNCATEGORIZED,
'Installment Loan' => PayeeService::CATEGORY_INSTALLMENT_LOAN,
'Credit Card' => PayeeService::CATEGORY_CREDIT_CARD,
'Utility' => PayeeService::CATEGORY_UTILITY,
'Mortgage' => PayeeService::CATEGORY_MORTGAGE,
'Entertainment' => PayeeService::CATEGORY_ENTERTAINMENT
],
'choices_as_values' => true
])
->add('amount', MoneyType::class, ['currency' => 'USD', 'grouping' => true])
->add('frequency', ChoiceType::class, [
'choices' => [
'Recurring' => PayeeService::FREQUENCY_RECURRING,
'One-time' => PayeeService::FREQUENCY_ONETIME
],
'choices_as_values' => true
])
->add('method', ChoiceType::class, [
'choices' => [
'ACH' => PayeeService::PAY_METHOD_ACH,
'Check' => PayeeService::PAY_METHOD_CHECK
],
'choices_as_values' => true
])
->add('dateLastPaid', DateType::class)
->add('dueDate', DateType::class)
->add('gracePeriod', IntegerType::class)
->add('balance', MoneyType::class, ['currency' => 'USD', 'grouping' => true])
->add('active', CheckboxType::class, ['label' => 'Active', 'data' => true])
->add('save', SubmitType::class, ['label' => 'Save Payee'])
;
}
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Payee'
));
}
}
Controller:
<?php
namespace AppBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
class FormController extends Controller
{
/**
* #Route("/_form/entity/{entity}", name="new_entity_form")
* #Method("GET")
*/
public function getFormForNewEntity(Request $request)
{
$rawName = $request->get('entity');
$content = $request->getContent();
$data = json_decode($content, true);
$formName = strtolower($rawName) . "_form";
$submitFunction = $data['submitFunction'];
$entityName = "AppBundle\Entity\\" . $rawName;
$entity = new $entityName();
$form = $this->createForm("\AppBundle\Form\\{$rawName}Type", $entity);
return $this->render('form/form.html.twig', [
'name' => $formName,
'form' => $form->createView(),
'submitFunction' => $submitFunction]);
}
/**
* #Route("/_form/entity/{entity}", name="new_entity_create")
* #Method("POST")
*/
public function saveFormForNewEntity(Request $request)
{
$em = $this->getDoctrine()->getManager();
$rawName = $request->get('entity');
$entityName = "AppBundle\Entity\\" . $rawName;
$entity = new $entityName();
$form = $this->createForm("\AppBundle\Form\\{$rawName}Type", $entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return new JsonResponse(['result' => true]);
} elseif ($form->isEmpty()) {
return new JsonResponse(['result' => false, 'errors' => 'form empty']);
} else {
return new JsonResponse(['result' => false, 'errors' => iterator_to_array($form->getErrors(true))]);
}
}
}
Form twig:
{{ form_start(form, {'attr': {'id':name, 'role':'form', 'submit.delegate':submitFunction}}) }}
{{ form_widget(form) }}
{{ form_end(form) }}
Aurelia component js:
import {InlineViewStrategy} from 'aurelia-framework';
import {customElement, bindable, inject} from 'aurelia-framework';
import $ from 'jquery';
import {HttpClient} from 'aurelia-http-client';
import 'fetch';
#customElement('symfony-form')
#inject(Element)
export class SymfonyForm {
#bindable entity;
constructor(element) {
this.content = '';
this.http = new HttpClient();
this.http.configure(config => {
config
.withBaseUrl('http://localhost:8000/');
});
this.element = element;
}
bind(binding, override) {
return this.http.get('_form/entity/' + this.entity, {'submitFunction': 'submit()'})
//.then(response => response.html())
.then(response => {
this.content = response.response;
});
}
submit() {
// application/x-www-form-urlencoded
this.http.createRequest('_form/entity/' + this.entity)
.withHeader('Content-Type', 'application/x-www-form-urlencoded')
.asPost()
.withContent($(this.element).find('form').serialize())
.send()
.then(response => {
alert(response.response);
});
//alert('submitted ' + this.entity);
// return this.http.post('_form/entity/' + this.entity, $(this.element).find('form').serialize())
// .then(response => {
// alert(response.response);
// });
}
}
aurelia component view:
<template>
<form role="form" submit.delegate="submit()">
<div innerHTML.bind="content"></div>
</form>
</template>
aurelia page:
<template>
<require from="form"></require>
<section class="au-animate">
<h2>${heading}</h2>
<form role="form" submit.delegate="submit()">
<div class="form-group">
<label for="fn">First Name</label>
<input type="text" value.bind="firstName" class="form-control" id="fn" placeholder="first name">
</div>
<div class="form-group">
<label for="ln">Last Name</label>
<input type="text" value.bind="lastName" class="form-control" id="ln" placeholder="last name">
</div>
<div class="form-group">
<label>Full Name</label>
<p class="help-block">${fullName | upper}</p>
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<symfony-form entity="Payee"></symfony-form>
</section>
</template>

I'm not an expert on SPAs, or JS frameworks, but from what I can see the problem is the lack of a CSFR field with the correct token and also that I don't believe your inputs are named correctly for symphony to read them correctly (I may have missed where this is handled so apologies if so). You need to have the input name formatted as below:
<input type="text" name="formname[formfield]" />
So for example I believe you need your name field to be:
<input type="text" name="payeetype[name]" />

Related

Prestashop after submit return page html

Hello I develop a module under Prestashop 1.6 and I am blocked on the submission of a form.
I add in my module a form with the hook "DisplayAdminOrderContentShip" which retrieves a tpl hook_button.tpl which displays my form (button)
relance
here is my tpl:
<div class="panel panel-default">
<div class="panel-heading">
<p>Export commande mecalux</p>
</div>
<div class="panel-body">
<p>Permet de relancer l'export vers Mecalux de la commande</p>
<form method="POST" action="#">
<button type="submit" value="1" id="exportordersubmit" name="exportordersubmit" class="btn btn-default pull-right">
<i class="process-icon-refresh"></i> {l s='Relancer l\'export' mod='exportorders'}
</button>
</form>
</div>
Here is my function:
public function hookDisplayAdminOrderContentShip($params)
{
$order = new Order(Tools::getValue('id_order'));
$status = (int)Configuration::get('EXPORTORDERS_STATUS_TRANSFERED_TO_WMS');
$statusError = (int)Configuration::get('EXPORTORDERS_STATUS_CMD_ERROR');
if (Tools::isSubmit('exportordersubmit')) {
if (isset($order) && (int)$order->valid == 1) {
if ($order->current_state != $status && $order->current_state != $statusError) {
return;
}
if (!$order->valid) {
return;
}
$customer = $order->getCustomer();
$deliveryAddress = new Address($order->id_address_delivery);
$id_country_delivery = $deliveryAddress->getCountryAndState($order->id_address_delivery);
$iso = new Country();
$userXml = [
'id_client' => $customer->id,
'email' => $customer->email,
'livraison' => $deliveryAddress,
'country_code_delivery' => $iso->getIsoById($id_country_delivery['id_country'])
];
$dateOrder = new DateTime($order->date_add);
$orderXml = [
'id' => $order->id,
'sorCode' => $order->reference,
'payment' => $order->payment,
'date' => $dateOrder->format('Y-m-d\TH:i:s') . 'Z',
];
$result = $this->fileXml($userXml, $orderXml, $order->getProducts());
if ((int)$result === 1) {
$order->setCurrentState($statusError, (int)$this->context->employee->id ? (int)$this->context->employee->id : 0);
$html = [
'message' => $this->displayError('Erreur de transmission au WMS'),
];
} else {
if ((int)$order->current_state !== (int)$status) {
$order->setCurrentState($status, (int)$this->context->employee->id ? (int)$this->context->employee->id : 0);
$order->wms_transfered = 1;
$order->save();
$html = [
'message' => $this->displayConfirmation('Transmise au WMS'),
];
}
}
}
}
$this->context->smarty->assign(
array(
'alert' => $html
)
);
return ($this->display(__FILE__, 'views/templates/hook/hook_button.tpl'));
}
and when I click here is the result of my page:
html
normally it should return an alert in the order detail page (admin) I do not see where my problem comes from have any idea?
Thank you for your help.
fetch

Yii2 Dynamic Form

I'm using wbraganca's dynamicform samples codes for mine own project. My code with its corresponding errors are as follows.
Under the view folder
_form.php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;
use frontend\models\Items;
use frontend\models\Employees;
use frontend\models\Departments;
use dosamigos\datepicker\DatePicker;
use wbraganca\dynamicform\DynamicFormWidget;
/* #var $this yii\web\View */
/* #var $model backend\models\Borrow */
/* #var $form yii\widgets\ActiveForm */
$js = '
jQuery(".dynamicform_wrapper").on("afterInsert", function(e, item) {
jQuery(".dynamicform_wrapper .panel-title-address").each(function(index) {
jQuery(this).html("Items: " + (index + 1))
});
});
jQuery(".dynamicform_wrapper").on("afterDelete", function(e) {
jQuery(".dynamicform_wrapper .panel-title-address").each(function(index) {
jQuery(this).html("Items: " + (index + 1))
});
});
';
$this->registerJs($js);?>
<div class="borrow-form">
<?php $form = ActiveForm::begin(['id'=>'dynamic-form']); ?>
<div class="row">
<div class="col-xs-4">
<?= $form->field($model,'dept_id')->dropDownList(
ArrayHelper::map(Departments::find()->all(),'id','dept_name'),
['prompt'=>'select departments'])
?>
</div>
<div class="col-xs-4">
<?=$form->field($model, 'return_date')->widget(
DatePicker::className(), [
'inline' => false,
'clientOptions' => [
'autoclose' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
</div>
</div>
<div class="padding-v-md">
<div class="line line-dashed"></div>
</div>
<!-- beginning of dynamic form -->
<?php DynamicFormWidget::begin([
'widgetContainer' => 'dynamicform_wrapper', // required: only alphanumeric characters plus "_" [A-Za-z0-9_]
'widgetBody' => '.container-items', // required: css class selector
'widgetItem' => '.item', // required: css class
'limit' => 10, // the maximum times, an element can be added (default 999)
'min' => 1, // 0 or 1 (default 1)
'insertButton' => '.add-item', // css class
'deleteButton' => '.remove-item', // css class
'model' => $modelsAddress[0],
'formId' => 'dynamic-form',
'formFields' => [
'items_id',
'unit',
'request',
'allowed',
],
]); ?>
<div class="panel panel-default">
<div class="panel-heading">
<h4><i class="glyphicon glyphicon-envelope"></i> Items
</h4>
</div>
<div class="panel-body">
<div class="container-items"><!-- widgetBody -->
<?php foreach ($modelsAddress as $i => $modelAddress): ?>
<div class="item panel panel-default"><!-- widgetItem -->
<div class="panel-heading">
<h3 class="panel-title pull-left">Items</h3>
<div class="pull-right">
<button type="button" class="add-item btn btn-success btn-xs"><i class="glyphicon glyphicon-plus"></i></button>
<button type="button" class="remove-item btn btn-danger btn-xs"><i class="glyphicon glyphicon-minus"></i></button>
</div>
<div class="clearfix"></div>
</div>
<div class="panel-body">
<?php
// necessary for update action.
if (! $modelAddress->isNewRecord) {
echo Html::activeHiddenInput($modelAddress, "[{$i}]id");
}
?>
<div class="row">
<div class="col-xs-4">
<?= $form->field($modelAddress, "[{$i}]items_id")->dropDownList(
ArrayHelper::map(Items::find()->all(),'id','item_name'),
['prompt'=>'select items']) ?>
</div>
<div class="col-xs-2">
<?= $form->field($modelAddress, "[{$i}]unit")->textInput(['maxlength' => true]) ?>
</div>
<div class="col-xs-2">
<?= $form->field($modelAddress, "[{$i}]request")->textInput(['maxlength' => true]) ?>
</div>
<div class="col-xs-2">
<?= $form->field($modelAddress, "[{$i}]allowed")->textInput(['maxlength' => true]) ?>
</div>
<div class="col-xs-2">
<?= $form->field($modelAddress, "[{$i}]unit_price")->textInput(['maxlength' => true]) ?>
</div>
</div><!-- .row -->
</div>
</div>
<?php endforeach; ?>
</div>
</div>
</div><!-- .panel -->
<?php DynamicFormWidget::end(); ?>
<!-- end dynamic form-->
<div class="row">
<div class="col-xs-5">
<?= $form->field($model,'emp_id')->dropDownList(
ArrayHelper::map(Employees::find()->all(),'id','emp_name'),
['prompt'=>'select employees'])
?>
<?= $form->field($model,'head_id')->dropDownList(
ArrayHelper::map(Employees::find()->all(),'id','emp_name'),
['prompt'=>'select dept heads'])
?>
<?= $form->field($model,'man_id')->dropDownList(
ArrayHelper::map(Employees::find()->all(),'id','emp_name'),
['prompt'=>'select stoke managers'])
?>
<?= $form->field($model,'keeper_id')->dropDownList(
ArrayHelper::map(Employees::find()->all(),'id','emp_name'),
['prompt'=>'select stoke keepers'])
?>
</div>
<div class="col-xs-5">
<?=$form->field($model, 'emp_date')->widget(
DatePicker::className(), [
'inline' => false,
'clientOptions' => [
'autoclose' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
<?=$form->field($model, 'head_date')->widget(
DatePicker::className(), [
'inline' => false,
'clientOptions' => [
'autoclose' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
<?=$form->field($model, 'man_date')->widget(
DatePicker::className(), [
'inline' => false,
'clientOptions' => [
'autoclose' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
<?=$form->field($model, 'keeper_date')->widget(
DatePicker::className(), [
'inline' => false,
'clientOptions' => [
'autoclose' => true,
'format' => 'yyyy-mm-dd'
]
]);?>
</div>
</div>
<div class="form-group">
<?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
</div>
<?php ActiveForm::end(); ?>
The create action under the controller
public function actionCreate()
{
$model = new Borrow();
$modelsAddress = [new Borrow];
if ($model->load(Yii::$app->request->post())) {
$modelsAddress = Model::createMultiple(Borrow::classname());
Model::loadMultiple($modelsAddress, Yii::$app->request->post());
// validate all models
$valid = $model->validate();
$valid = Model::validateMultiple($modelsAddress) && $valid;
if ($valid) {
$transaction = \Yii::$app->db->beginTransaction();
try {
if ($flag = $model->save(false)) {
foreach ($modelsAddress as $modelAddress) {
$modelAddress->id = $model->id;
if (! ($flag = $modelAddress->save(false))) {
$transaction->rollBack();
break;
}
}
}
if ($flag) {
$transaction->commit();
return $this->redirect(['view', 'id' => $model->id]);
}
} catch (Exception $e) {
$transaction->rollBack();
}
}
}
return $this->render('create', [
'model' => $model,
'modelsAddress' => (empty($modelsAddress)) ? [new Address] : $modelsAddress
]);
}
The Model Class under the Model Folder
<?php
namespace frontend\models;
use Yii;
use yii\helpers\ArrayHelper;
class Model extends \yii\base\Model
{
/**
* Creates and populates a set of models.
*
* #param string $modelClass
* #param array $multipleModels
* #return array
*/
public static function createMultiple($modelClass, $multipleModels = [])
{
$model = new $modelClass;
$formName = $model->formName();
$post = Yii::$app->request->post($formName);
$models = [];
if (! empty($multipleModels)) {
$keys = array_keys(ArrayHelper::map($multipleModels, 'id', 'id'));
$multipleModels = array_combine($keys, $multipleModels);
}
if ($post && is_array($post)) {
foreach ($post as $i => $borrow) {
if (isset($borrow['id']) && !empty($borrow['id']) && isset($multipleModels[$borrow['id']])) {
$models[] = $multipleModels[$borrow['id']];
} else {
$models[] = new $modelClass;
}
}
}
unset($model, $formName, $post);
return $models;
}
}
It gives the following error when I run my code:
PHP Fatal Error – yii\base\ErrorException Class 'frontend\controllers\Model' not found as shown below.
It looks like you have not namespaced frontend\models\Model in the controller.
Add there at the beginning:
use frontend\models\Model;

MVC Kendo Grid with custom popup editor using MultiSelect - can't get selected items in model

The title says it all.
POPUP FORM:
#using Kendo.Mvc.UI
#using Batc.AgileApp.Web.Areas.ProductReuse.Models
#model BomViewModel
#Html.HiddenFor(m => m.BomId)
#Html.HiddenFor(m => m.Row)
#Html.HiddenFor(m => m.UserWorkSessionId)
<div class="container-fluid">
<div class="form-group row">
<div class="col-xs-4 col-sm-4">
<span>
#Html.LabelFor(model => model.ProductClass)
</span>
<br/>#(Html.Kendo().DropDownListFor(m => m.ProductClass)
.DataTextField("Text")
.DataValueField("Value")
.HtmlAttributes(new {style = "width:125px"})
.DataSource(source =>
{
source.Read(read => { read.Action("GetDropDownLookups", "AjaxProductReuse", new {id = "ProductClass"}); });
})
)
<div style="font-weight: normal;">
#Html.ValidationMessageFor(model => model.ProductClass)
</div>
</div>
<div class="col-xs-4 col-sm-4">
<span>
#Html.LabelFor(model => model.ProgramSelectedList)
</span>
#(Html.Kendo().MultiSelectFor(m => m.ProgramSelectedList)
.Placeholder("Select program...")
.HtmlAttributes(new {style = "width:200px"})
.DataSource(source =>
{
source.Read(read => { read.Action("GetLookups", "AjaxProductReuse", new {id = "Program"}); });
})
)
<div style="font-weight: normal;">
#Html.ValidationMessageFor(model => model.ProgramSelectedList)
</div>
</div>
</div>
</div>
GRID FORM (cshtml view):
#using Batc.AgileApp.Web.Areas.ProductReuse.Models
#using Kendo.Mvc.UI
#model AssemblyViewModel
#using (Html.BeginForm("Assembly", "ProductReuse", FormMethod.Post, new {id = "frmStartScreen"}))
{
#Html.HiddenFor(m => m.Status)
#Html.HiddenFor(m => m.UserWorkSessionId)
#Html.HiddenFor(m => m.GlobalPartNum)
#(Html.Kendo().Grid<BomViewModel>()
.Name("bom-prGrid-kendoGrid")
.HtmlAttributes(new {#class = "prGrid"})
.ClientRowTemplate("")
.Columns(columns =>
{
columns.Command(cmd => cmd.Edit()).Width(80);
columns.Bound(g => g.BomId).Hidden();
columns.Bound(g => g.IsEditable).Hidden();
columns.Bound(g => g.Row).Width(75).Title("Row");
columns.Bound(p => p.Program).Width(100).Title("Program");
columns.Bound(p => p.ProductClass).Width(100).Title("Product<br/>Class");
columns.Bound(p => p.ResponsibleEng).Width(120).Title("Resp Eng");
columns.Bound(p => p.ProjectNum).Width(100).Title("Project<br/>No");
columns.Bound(p => p.AccessControl).Width(150).Title("Access Control");
})
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => { model.Id(g => g.BomId); })
.PageSize(100)
.Read(r => r.Action("GetCloneAssembly", "AjaxProductReuse").Data("ProductReuseGridReadData"))
.Update(u => u.Action("UpdateBomItem", "AjaxProductReuse").Type(HttpVerbs.Post))
.Events(e => e.Error("ajax_error").Sync("dataSource_sync").Change("dataSource_change"))
)
.Events(e => e.DataBound("onDataBound").Edit("onEdit"))
.Pageable(pager => pager
.Input(true)
.Numeric(true)
.Info(true)
.PreviousNext(true)
.Refresh(true)
.PageSizes(new int[] {100, 250, 500, 1000})
)
.Sortable()
.Scrollable()
.Filterable()
.Editable(editable => editable.Mode(GridEditMode.PopUp).TemplateName("BOMForm").Window(w => w.Title("Manage BOM Item").Name("BOMForm")))
.Resizable(resizing => resizing.Columns(true)).Reorderable(reorder => reorder.Columns(true))
)
}
Model (properties of interest):
[MetadataType(typeof(BomViewModelMetaData))]
public class BomViewModel: BomModel
{
public int BomId { get; set; }
public int Row { get; set; }
public int UserWorkSessionId { get; set; }
public string ProductClass { get; set; }
public string Program { get; set; }
public List<string> ProgramSelectedList { get { return Program.ToList(); } set { Program = value.ToDelimitedString(); } }
}
My (ajax) controller looks like:
public JsonResult UpdateBomItem([DataSourceRequest] DataSourceRequest request, BomViewModel bomViewModel) // [Bind(Prefix = "models")]
{
var command = _mapper.Map<BomModel>(bomViewModel);
var commandResponse = _productReuseService.UpdateBomItem(command);
var response = _mapper.Map<List<BomViewModel>>(commandResponse);
return Json(ToDataSourceResult(response, request, modelState: ModelState));
}
The problem I am encountering is the data being posted to my controller. It looks like this in fiddler (where the first 3 items map to the first object in the controller, the remainder being the model):
sort=
&group=
&filter=
&Program=PROGRAM_ORIGINAL
&ProgramSelectedList[0]=PROGRAM_01
&ProgramSelectedList[1]=PROGRAM_02
&UserWorkSessionId=45
&Row=10
&ProductClass=1
&BomId=151927
What I expected was:
sort=
&group=
&filter=
&Program=PROGRAM_01, PROGRAM_02
&ProgramSelectedList=PROGRAM_01
&ProgramSelectedList=PROGRAM_02
&UserWorkSessionId=45
&Row=10
&ProductClass=1
&BomId=151927
Is there a "special" setting in Kendo or JQuery or .NET to make this list behave correctly? I currently am using Kendo in MVC HTML Helper mode only. This means I have almost no JS propping up my desired actions on the UI side of things.
This is an internal LOB app, low usage, minimal users.
After much digging and frustration the answer is pretty simple. I needed to add a JS helper to put the data into a format the MVC Model Binder could understand.
<script>
function getUpdatedBomRowData() {
var program = $("#ProgramSelectedList").data("kendoMultiSelect").value().toString();
return {
program: program
}
}
</script>
And then on the grid's datasource update action I added a Data(...) method:
.DataSource(dataSource => dataSource
.Ajax()
.Model(model => { model.Id(g => g.BomId); })
.PageSize(100)
.Read(r => r.Action("GetCloneAssembly", "AjaxProductReuse").Data("ProductReuseGridReadData"))
.Update(u => u.Action("UpdateBomItem", "AjaxProductReuse").Type(HttpVerbs.Post).Data("getUpdatedBomRowData"))
.Events(e => e.Error("ajax_error").Sync("dataSource_sync").Change("dataSource_change"))
)
The JS will then put a comma delimited string into the Program property before sending to the controller. Since Program is being used as (A) a DB representation of the table field, and (B) a backing field for List ProgramSelectedList, my code seems to be happy now.

Yii 2.0 hidden field value not modifiable using javascript

In my model I have a hidden field.I am modifying its value using javascript (jQuery).But when I submit the form to model, it still contains its initial value instead of values modified via javascript.I have checked whether javascript is modifying the values, and is confirmed that values are being modified.But when form is submitted it is sending initial values.
Code is given below
<?php
/*Model -- wrong_answers is my hidden field*/
namespace app\models;
use yii;
use yii\db;
use yii\base\Model;
use yii\web\UploadedFile;
class QuestionModel extends Model
{
public $quiz_id = null;
public $question = '';
public $choices = '';
public $explanation ="";
public $hints = array();
public $correct_answer = "";
public $wrong_answers = '{}';//when populating from already entered data use {"a":"as"} format instead of {'a':'as'}
public $wrong_answer = "";
public function rules()
{
return [
[['quiz_id'], 'safe'] ,
[['question'], 'required'] ,
[['correct_answer'], 'required'] ,
[['wrong_answers'], 'safe'] ,
[['wrong_answer'], 'safe'] ,
[['explanation'],'required']
];
}
public function get_quiz($quiz_id) {
$ret = array();
$command = Yii::$app->db->createCommand("CALL get_quiz(:qz_id)");
$command->bindParam(":qz_id", $this->quiz_id);
$result = $command->queryAll();
if(sizeof($result) > 0) {
$ret = $result[0] ;
}
return $ret;
}
public function save_question() {
$ret = false;
//echo "quiz- id is ".$this->quiz_id;
$quiz_details = $this->get_quiz($this->quiz_id);
if(sizeof($quiz_details)) {
$quiz_data = $quiz_details['quiz_data'];
$quiz_data = json_decode($quiz_data);
$choices = [];
echo $this->wrong_answers;
exit;
$wrong_answers_array = json_decode($this->wrong_answers);
if($this->wrong_answer)
array_push($wrong_answers_array, $this->wrong_answer);
print_r($wrong_answers_array);
exit;
foreach($wrong_answers_array as $wr_ans) {
array_push($choices,array('choice'=>$wr_ans));
}
$question_data = array('question'=>$this->question,'explanation'=>$this->explanation,'choices'=>$choices);
$ret = false;
}
return $ret;
}
public function getHint($key) {
return $this->hints[$key];
}
}
Controller - actionAdd_question is the action
<?php
namespace app\controllers;
use Yii;
use yii\filters\AccessControl;
use yii\web\Controller;
use yii\filters\VerbFilter;
use app\models\QuizModel;
use app\models\QuestionModel;
use yii\web\UploadedFile;
global $username;
class QuizController extends Controller
{
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'only' => ['logout'],
'rules' => [
[
'actions' => ['logout'],
'allow' => true,
'roles' => ['#'],
],
],
],
'verbs' => [
'class' => VerbFilter::className(),
'actions' => [
'logout' => ['post'],
],
],
];
}
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
];
}
public function actionEntry()
{
}
public function actionView_all() {
$request = Yii::$app->request;
$layout_params=array(
'username'=>'admin',
'sidebar_menu1_class' =>'active',
'sidebar_menu12_class' =>'active',
'dash_title' => 'Courses',
'dash_sub_title'=>'View all'
);
$message = '';
$data = array();
$layout_params['scripts'] = array("view-all-modules.js");
/*$model = new ViewAllCompaniesModel();
$pagination_data = $model->getTotalCompanies();
$layout_params['js_variables'] = array(
'totalCompanyPages'=>$pagination_data['total_page_count'],
'csrfToken' => "'".$request->csrfToken."'" ,
'csrfTokenName' => "'".$request->csrfParam."'"
);
*/
return $this->render('view-all-modules', [
'layout_params'=>$layout_params,
'message' =>$message,
'data' =>$data
]);
}
public function actionAdd() {
$layout_params=array(
'username'=>'admin',
'sidebar_menu1_class' =>'active',
'sidebar_menu12_class' =>'active',
'dash_title' => 'Quiz',
'dash_sub_title'=>'Add new quiz'
);
$message = array();
$request = Yii::$app->request;
$proceed = true;
$parent_course_id = null;
$req_params = $_POST;
$layout_params['scripts'] = array("add-quiz.js");
$model = new QuizModel();
if(!$model->quiz_id) {
if ($model->load($request->post()) && $model->validate()) {
$params = $request->post();
$model->save_quiz();
$message['title'] = 'Wow !';
$message['body'] = 'Successfully added quiz '.$model->quiz_title;
} else {
}
} else {
}
return $this->render('add-quiz', ['model' => $model,
'layout_params'=>$layout_params,
'message' =>$message
]);
//return $this->render('add-company',$data);
}
public function actionSave() {
//print_r($_POST);
}
public function actionAdd_question() {
print_r($_POST);
$layout_params=array(
'username'=>'admin',
'sidebar_menu1_class' =>'active',
'sidebar_menu12_class' =>'active',
'dash_title' => 'Quiz',
'dash_sub_title'=>'Add question'
);
$request = Yii::$app->request;
$message = array();
$layout_params['scripts'] = array("add-question.js");
$model = new QuestionModel();
if($request->get('q_id')) {
$model->quiz_id = $request->get('q_id');
if ($model->load($request->post()) && $model->validate()) {
$model->save_question();
} else {
echo "yo yo";
}
return $this->render('add-question', ['model' => $model,
'layout_params'=>$layout_params,
'message' =>$message
]);
} else {
}
}
public function actionIndex()
{
$data = array(
'layout_params'=>array(
'username'=>'admin',
'sidebar_menu11_class' =>'active'
)
);//
}
public function actionLogout()
{
Yii::$app->user->logout();
return $this->goHome();
}
}
View
/*Assigning the parameters to be accessible by layouts*/
foreach($layout_params as $layout_param => $value) {
$this->params[$layout_param] = $value;
}
?>
<div class="form-group">
</div>
<div class="col-md-12">
<div class="box box-primary">
<div class="box-header">
<h3 class="box-title">Add Question</h3>
</div><!-- /.box-header -->
<!-- form start -->
<?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]); ?>
<input type = 'hidden' id = 'test' name = 'test' />
<div class="box-body">
<?php if(isset($message)&&sizeof($message)): ?>
<div class="form-group">
<div class="callout callout-info alert-dismissible">
<h4><?php if(isset($message['title']))echo $message['title'];?></h4>
<p>
<?php if(isset($message['body']))echo $message['body'];?>
</p>
</div>
</div>
<?php endif;?>
<div class="form-group">
<?= $form->field($model, 'question')->textInput(array('class'=>'form-control')); ?>
</div>
<div class="form-group">
<?= $form->field($model, 'correct_answer')->textInput(array("class"=>"form-control",'id'=>'correct_answer')); ?>
<?= Html::activeHiddenInput($model, 'wrong_answers',array('id'=>'wrong_answers')) ;?>
<?= Html::activeHiddenInput($model, 'quiz_id',array('id'=>'quiz_id')) ;?>
</div>
<div class="form-group">
<?= $form->field($model, 'wrong_answer')->textInput(array("class"=>"form-control ",'id'=>'wrong_answer')); ?>
<button id = 'add-answer' type = "button">Add Another</button>
<?= Html::activeHiddenInput($model, 'wrong_answers',array('id'=>'wrong_answers')) ;?>
<?= Html::activeHiddenInput($model, 'quiz_id',array('id'=>'quiz_id')) ;?>
</div>
<div class="form-group" id ='wrong-group'>
<h3>Wrong Answers</h3>
<!-- The following dummy html is used for generating html inside javascript -->
<ul class="edit-list-dummy" id ="edit-list-dummy">
<li> <button class="btn btn-danger" id = 'dummy-wrong-ans-delete' onClick = "deleteWrongAnswer(this.name)" type ="button">Delete</button> <span id ='dummy-wrong-answer'>Hello I am a wrong answer here</span>
</ul>
<ul class="edit-list" id = 'wrong-answers'>
</ul>
</div>
<div class="form-group">
<?= $form->field($model, 'explanation')->textArea(array("class"=>"form-control",'id'=>'explanation')); ?>
</div>
</div><!-- /.box-body --> <div class="box-footer">
<?= Html::submitButton('Save Question', ['class' => 'btn btn-primary','onclick'=>'this.preventDefault']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
</div>
Javascript -#wrong_answers is my hidden input id
var wrongAnswers = {};//{1:answer1,2:answer2...};
var randCount = 0;//radom count for setting as wrongAnswers attribute
//initialise wrong answers json from database
$(document).ready(function() {
console.log($('#wrong_answers').val());
wrongAnswers = jQuery.parseJSON($('#wrong_answers').val());
console.log(wrongAnswers);
$('#add-answer').click(function() {
var wrongAns = $('#wrong_answer').val().trim();
if(wrongAns) {
wrongAnswers[randCount] = wrongAns;
randCount++;
generateWrongAnswers();
$('#wrong_answer').val("");
// alert($('#wrong_answers').val());
}
});
generateWrongAnswers();
});
function generateWrongAnswers() {
$('#wrong-group').hide();
var html = '';
for(var wrongIdx in wrongAnswers) {
//console.log("w is ".wrongAnsIdx);
$('#dummy-wrong-answer').html(wrongAnswers[wrongIdx]);
$('#dummy-wrong-ans-delete').attr('name',wrongIdx);
html += $('#edit-list-dummy').html();
}
if(html) {
$('#wrong-group').show();
$('#wrong-answers').html(html);
}
var jsonData = JSON.stringify(wrongAnswers);
$('#wrong_answers').val(jsonData);
// $('#test').val(jsonData);
//$('#correct_answer').val("Mallu");
// alert($('#wrong_answers').val());
}
function deleteWrongAnswer(idx) {
delete wrongAnswers[idx];
generateWrongAnswers() ;
}
Finall solved it. The issue is that, I accidentally included two hidden input fields with same id.Removed one and solved

Recaptcha doesn't work with ajax and partial views

I'm using Recaptcha in my MVC4 web app. It was working correctly when it was embedded in the form but when I moved the #Html.Raw(Html.GenerateCaptchaHelper()) to partial view and trying to call this partial view via ajax request, it doesn't work!
Extension code :
public static string GenerateCaptchaHelper(this HtmlHelper helper)
{
var captchaControl = new Recaptcha.RecaptchaControl
{
ID = "recaptcha",
Theme = "clean",
PublicKey = ************,
PrivateKey = **********************,
Language = "En"
};
var htmlWriter = new HtmlTextWriter(new StringWriter());
captchaControl.RenderControl(htmlWriter);
return htmlWriter.InnerWriter.ToString();
}
my partial view is has the code like :
<p>#Html.Raw(Html.GenerateCaptchaHelper())</p>
and inside my controller
public PartialViewResult Captcha()
{
return PartialView();
}
and inside my main view:
#using (Html.BeginForm("Login", "Account", new { returnUrl = ViewData["ReturnUrl"] }, FormMethod.Post,null))
{
#Html.AntiForgeryToken()
<form role="form">
<div class="form-group">
<label>#Html.LabelFor(m => m.Email)</label><br />
#Html.TextBoxFor(m => m.Email, null, new { #class = "form-control", autocomplete = "off" })
</div>
<div class="form-group">
<label>#Html.LabelFor(m => m.Password)</label><br />
#Html.PasswordFor(m => m.Password, new { #class = "form-control", autocomplete = "off" })
</div>
<div id="captchaView" class="form-group">
</div>
<button type="submit">Login</button>
</div>
</div>
</form>
}
and the javascript is :
$.ajax({
url: '/Account/Captcha',
type: 'GET',
success: function(data) {
$('#captchaView').html(data);
}
});
Could you please help me to figure out why?