The story.
I'm trying to calculate product cost's based on multiple varying factors. My system currently works perfectly using PHP functions however I would like to add some Ajax in order to produce a more user friendly experience.
How I currently do it.
Entities
//entity/ProductRecipe.php
public function productcost2amountcost() {
$this->productcost = null;
$am = $this->amount;
$cu = $this->product->getCostunit();
$productcost = $am * $cu;
$this->productcost = $productcost;
$this->recipe->fixRecipecost();
$this->recipe->fixCostperyield();
}
//entity/Recipe.php
public function fixRecipecost() {
$this->recipecost = 0;
foreach ($this->product AS $pc) {
$this->recipecost += $pc->getProductcost();
$this->setRecipecost($this->recipecost);
}
}
public function fixCostperyield(){
$this->costperyield = null;
$cy = $this->recipeyield;
$rc = $this->recipecost;
$this->costperyield = $rc / $cy;
}
Forms
//Form/RecipeType.php
$builder
->add('recipename', 'text', array(
'label' => 'Recipe Name'))
->add('recipeyield', 'number', array(
'label' => 'Recipe Yield'))
->add('product', 'collection', array(
'label' => 'Ingredients',
'type' => new ProductRecipeType(),
'allow_add' => true,
'by_reference' => false,
'allow_delete' => true,
));
//Form/ProductRecipeType.php
$builder
->add('product', 'entity', array(
'class' => 'BCInventoryBundle:Product',
'property' => 'prodlist',
))
->add('amount', 'number', array(
'label'=>'Quantity',
))
->add('measure', 'entity', array(
'class' => 'BCInventoryBundle:Measures',
'property' => 'unit',
))
->add('productcost' ,'money', array(
'currency' => false,
'read_only' => 'true',
))
;
As I stated before this all works fine, albeit a bit boring and static.
Issue
As you can see from the picture. The ProductRecipe is used as a collection of form's from within the Recipe form. What I want is once the User has selected a product from the Database (Butter) and stated a quantity (1) and measure (kg) I need Ajax to first get the UnitCost (all Units get converted to Grams and update a filed called Unitcost)
1kg convert to g = 1000, 1000 * unitcost (0.0079600000) = £7.96 <- This needs to be put into the ProductCost field of the form.
Any help would greatly be appreciated even a point in the right direction would be amazing. I've spent hours Google-ing but the stuff that comes up never quite seems to be what I need especially when it comes to Symfony2 related.
How do I run the productcost2amountcost() function using Ajax in order to fill the ProductCost field without a page refresh.
Thank-you in advance. Doug.
The Answer
Thank's to Santiag00 after much trial and error for us both we got it working. He's updated his part but I'd like to elaborate a bit.
Javascript
//Calc.js
$(document).on('change', '.products, .amounts, .unit', function(event) {
var amount = $(this).parent().parent().parent().find('.amounts').val();
var productId = $(this).parent().parent().parent().find('.products').val();
var unit = $(this).parent().parent().parent().find('.unit').val();
var productCostField = $(this).parent().parent().parent().find('.product-costs');
//The above assign a Var to each of the field's needed for the JS
console.log(productCostField);
console.log("Amount: " + amount + " - ProductID: " + productId + " - unit: " + unit);
if (amount == "" || productId == "" || unit == "") {
// Don't make the Ajax call if you are missing one of the two values
return false;
}
// This will be triggered every time a product or amount input field is changed
$.post(
Routing.generate('calculate_cost'),
//This line is what connects to the Function in the controller and defined in routing.yml. Made easier by
//https://github.com/FriendsOfSymfony/FOSJsRoutingBundle/blob/master/Resources/doc/index.md
{
// Use the corresponding amount and product ID
product: productId, amount: amount, unit: unit,
},
function(data) {
data = JSON.parse(data);
if (!data.success) {
// An error was thrown in the controller
alert(data.message);
}
else {
// Update the corresponding productCost field using the data from the controller
console.log("Product cost: " + data.productCost);
productCostField.val(data.productCost);
}
}
);
}
);
The Route Called from the above JS.
//routing.yml
calculate_cost:
pattern: /productcost
defaults: { _controller: "BCInventoryBundle:ProductRecipe:getProductCost" }
options:
expose: true
Last of all, the function called from the above JS.
//ProductRecipeController.php
public function getProductCostAction(Request $request) {
$amount = $request->request->get('amount', null);
$productId = $request->request->get('product', null);
$unit = $request->request->get('unit', null);
if (empty($amount) || empty($productId)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Bad input')));
}
$em = $this->getDoctrine()->getManager();
$product = $em->getRepository('MyBundle:Product')->find($productId);
$u = $em->getRepository('MyBundle:Measures')->find($unit);
$mass = new Mass($amount, $u->getUnit());
$fam = $mass->toUnit('g');
if (empty($product)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Invalid product')));
}
$productCost = $product->getCostunit() * $fam;
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => true, 'productCost' => $productCost)));
}
I really hope this can be helpful to other people out there. If you find it useful please up-vote Santiag00 we spent ages trying to figure this out. The main part to notice is how we had to select the field's because of how nested they were when using embedded forms in Symfony.
One solution would be to install "FOSJsRoutingBundle" (https://github.com/FriendsOfSymfony/FOSJsRoutingBundle) to expose routes in Javascript. That way you would be able to create a new action in a Controller that would calculate a product cost and return it as a JSON to the HTML.
The action in the controller could look something like this:
/**
* #Route("/productcost", name="calculate_cost", options={"expose"=true})
* #Method("POST")
*/
public function getProductCostAction(Request $request) {
$amount = $request->request->get('amount', null);
$productId = $request->request->get('product', null);
if (empty($amount) || empty($productId)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Bad input')));
}
$product = $this->getDoctrine()->getManager()->getRepository('ProductBundle:ProductRecipe')->findOneBy(array('id' => $productId));
if (empty($product)) {
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => false, 'message' => 'Invalid product')));
}
$productCost = $product->getCostunit() * $amount;
return new \Symfony\Component\HttpFoundation\Response(json_encode(array('success' => true, 'productCost' => $productCost)));
}
And then the AJAX call could look like this:
<script>
$(document).on('change', '.products, .amounts', function(event) {
var amount = $(this).parent().children('.amounts').val();
var productId = $(this).parent().children('.products').val();
if (amount == "" || productId == "") {
// Don't make the Ajax call if you are missing one of the two values
return false;
}
// This will be triggered every time a product or amount input field is changed
$.post(
Routing.generate('calculate_cost'),
{
// Use the corresponding amount and product ID
amount: amount,
product: productId
},
function(data) {
data = JSON.parse(data);
if (!data.success) {
// An error was thrown in the controller
alert(data.message);
}
else {
// Update the corresponding productCost field using the data from the controller
$(this).parent().children('.product-costs').val(data.productCost);
}
}
);
});
</script>
productcost2amountcost seems too complex and it has strong relation to state of the model.
If you want to update DB (or some store) each time client sends ajax request, you can use productcost2amountcost. But it is expensive and risky. (You must control the order of requests) [Solution1]
If you want to treat requests more simply, I think you should convert productcost2amountcost to stateless (as a procedure) and some small logic. (State managed by client) [Solution2]
New procedures receive some parameter (e.g. product, quantity, measure) through ajax, and send response (e.g. productcost).
(If you use temporary models (non-stored), you can use productcost2amountcost. But you should remove reference to Recipe from productcost2amountcost)
But in this case, I think you don't have to use ajax.
You can calculate all costs by javascript with the form data (include hidden unit cost and measure scale) for usability, and re-calculate in server side for update at last. [Solution3]
Logic duplication and calculation of different architecture are damn, but it is maybe simple solution.
Related
i try to keep it short.
I want to change the possible choice opotion of my ChoiceType(N.2), depending on another ChoiceType(N.1).
My ChoiceType(N.1) is unmapped and has the Option "Yes" or "No"
My ChoiceType(N.2) is mapped and filled with categorys out of an database.
The database has the Columns ID(int) | Name(string) |
Revenue(boolean)
So if the user chooce the Option Yes, i want all Categorys in the ChoiceType (N.2) with the revenue of 1(true). If the user choose No, i want to display all choice options with the categorys with the revenue of 0 (boolean)
I've done a lot of research but I just can't get it to work.
I mainly focus on de documentaion https://symfony.com/doc/current/form/dynamic_form_modification.html, but there both ChoiceTyps are Entitys, not just one. I should almost have it, but I don't know what's missing.
Here are the important parts of my code:
EntryForm:
->add('choice', ChoiceType::class, [
'choices' => [
'No' => 0,
'Yes' => 1,
],
'data'=>0,
'mapped' => false,
])
$formModifier = function (FormInterface $form, $choice) {
$revenue = $choice;
$user = $this->security->getUser();
$userId = $user->getId();
$form->add('category', EntityType::class,[
'class'=>Category::class,
'query_builder' => function(CategoryRepository $repository) use($userId,
$revenue) {
$qb = $repository->createQueryBuilder('u');
return $qb
->where('u.user=' .$userId, 'u.revenue='. $revenue );
}, ]);
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
$form = $event->getForm();
$choice = $form->get('choice')->getData();
$formModifier($event->getForm(), $choice);
}
);
$builder->get('choice')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
$choice = $event->getForm()->getData();
$formModifier($event->getForm()->getParent(), $choice);
}
);
AJAX
var $choice = $('#entry_choice');
$choice.change(function() {
var $form = $(this).closest('form');
var data = {};
var choice = $('#entry_choice').val();
data= choice;
data[$choice] = 1;
$.ajax({
url: $form.attr('action'),
type: $form.attr('method'),
data : data,
complete: function(html) {
console.log( data);
$('#entry_category').replaceWith(
$(html.responseText).find('#entry_category'));
}
});
});
I think I don't understand the data passed from ajax correctly.
I am trying to achieve the following: If the user change the ChoiceType from No to Yes, pass the variable $choice with the value 1 to the form. In the form at the $formModifier it should change the variable $revenue to $choice, so that i can filter with my query_builder through all categorys where revenue is 1. ('u.revenue='. $revenue)
Kind regards Magnus
Instead of data[$choice] = 1; try data[$choice.attr('name')] = 1;
Symfony expects the data to be sent from the front end in a specific format.
If you inspect the source of the generated html form, you will see that format.
I am very much new to laravel framework.
I have one form , which i need to update on submit button click.
when submit button clicks control goes to controller.php 's update() function .
But I am unable to edit any field's value.
here is my code.
public function update($id)
{
//echo "<pre>";print_r(Input::all());exit;
$product = $this->product->find($id);
$input = Input::only('designer', 'sku', 'name', 'display_name', 'description', 'price', 'main_category', 'sub_category', 'lead_time', 'sizing', 'woven', 'body_fabric', 'lining_fabric', 'fit', 'primary_color', 'secondary_color', 'care_label', 'neck_type', 'closure', 'trims', 'special_finishings', 'image1', 'image2', 'image3', 'image4', 'image5','top', 'combo_products', 'keywords', 'visibility', 'featured');
//echo "<pre>";print_r($input);exit;
try
{
$this->adminNewProductForm->validate($input);
} catch(\Laracasts\Validation\FormValidationException $e)
{
return Redirect::back()->withInput()->withErrors($e->getErrors());
}
$slug = Str::slug(Input::get('name'));
$slug = $this->product->getSlug($slug);
$input = array_add($input, 'slug', $slug);
DB::transaction(function() use($product, $input)
{
$product->fill($input)->save();
$stock_count = 0;
if(!empty(Input::get('xsmall_size')))
{
$rows = DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->get();
$stock_count += Input::get('xsmall_stock');
if(!empty($rows))
{
DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->update(array('variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
} else {
DB::table('products_variants')->insert(array('product_id' => $product->id, 'variant_name' => 'XS', 'variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
}
}
$input = array();
$input['flagship_status'] = Input::get('flagship_status');
if(Input::get('flagship_status'))
{
$input['stock_count'] = Input::get('small_stock');
}else {
$input['stock_count'] = $stock_count;
}
$product->fill($input)->save();
});
//echo "<pre>";print_r(Input::all());exit;
return Redirect::back()->withFlashMessage('Product Updated Successfully!');
}
Also I cant understand , what is going on by this line ? because i did not find validate function anywhere in my code.
$this->adminNewProductForm->validate($input);
I need to update table products not products_variants.
validate is inherited from the FormRequst class.
https://laravel.com/api/5.0/Illuminate/Foundation/Http/FormRequest.html#method_validate
You've provided too much code and too little information. You said you need to update a specific table, but yet there are two lines where you are very intentionally manually updating a database entry.
This is one of them:
DB::table('products_variants')->where('product_id', $product->id)->where('variant_name', 'XS')->update(array('variant_specs' => Input::get('xsmall_size'), 'price_change' => Input::get('xsmall_price'), 'total_stock' => Input::get('xsmall_stock'), 'stock_used' => 0));
When you call this:
$product->fill($input)->save();
It also saves 'dirty' (modified) models that also belong to it, which can include products_variants relationships. From the sound of it, you are incorrectly applying changes directly through SQL, and then the model's save method is overwriting it.
You seem unclear about what your code is actually doing, and I would strongly suggest simplifying it down and adding in code as you begin to understand what each line does. I think your question is the byproduct of copying an example and adding your own work without understanding how Laravel handles relationships and models. There is almost never a good reason to use raw SQL or DB statements.
In a form event, setting a field 'attr' => array('readonly' => 'readonly') is rendered as "disabled" = "1". This is not the desired effect. A disabled select field persists a null value on submit. A readonly field should retain and persist the displayed value. Or so I thought. So how to get the value to remain unchanged and unchangeable?
Edit;
A hidden field does not do the trick. choice_attr does not help either.
I'm voting to close this question. I've not discovered any method for displaying a disabled entity field and also retain the value. If you've got any idea on how that's done...
An example (in Symfony 2.8.3):
The Household entity has six attributes, each of which is an entity in a OneToMany relationship to Household. (The application has other entities which have similar attributes.) The Housing entity/attribute of Household has two properties: housing and enabled. The application's client can set a property to enabled = no if they no longer intend to track that property.
If a property is set to enabled = no its availability in a new or edit Household form is readily eliminated by including a where clause in the entity field's query builder, e.g., ->where("h.enabled=1"). However, doing so causes the disabled property to be set to null. Thus the need for retaining the value somehow.
The ideal solution would be a service for these attribute entity fields that would both display values and retain if enabled is no.
I have tried using an event listener, a hidden field, choice_attr, modifying the form template and the form theme all to no avail. For example, a hidden field is text when an entity field is required. This doesn't mean it can't be done, only that I haven't stumbled on the proper method.
The eventual solution: a service using Doctrine metadata to get disabled entity fields, form class modifications, and, for ManyToMany relationships, some jquery and invisible template entry.
Service functions:
/**
* Create array of disabled fields of an entity object
*
* #param type $object
* #return array
*/
public function getDisabledOptions($object) {
$values = [];
$className = get_class($object);
$metaData = $this->em->getClassMetadata($className);
foreach ($metaData->associationMappings as $field => $mapping) {
if (8 > $mapping['type']) {
$fieldName = ucfirst($field);
$method = 'get' . $fieldName;
if (method_exists($object->$method(), 'getEnabled') && false === $object->$method()->getEnabled()) {
$values[] = $fieldName;
}
}
}
$manyToMany = json_decode($this->getMetaData($object), true);
foreach(array_keys($manyToMany) as $key) {
$values[] = $key;
}
return $values;
}
/**
* Get array of disabled ManyToMany options
*
* #param Object $object
* #return array
*/
public function getMetaData($object) {
$data = array();
$className = get_class($object);
$metaData = $this->em->getClassMetadata($className);
foreach ($metaData->associationMappings as $field => $mapping) {
if (8 === $mapping['type']) {
$data[$field] = $this->extractOptions($object, $field);
}
}
return json_encode($data);
}
Controller use of service:
$searches = $this->get('mana.searches');
$disabledOptions = $searches->getDisabledOptions($household);
$metadata = $searches->getMetadata($household);
...
$form = $this->createForm(HouseholdType::class, $household, $formOptions);
...
return $this->render('Household/edit.html.twig',
array(
'form' => $form->createView(),
....
'metadata' => $metadata,
));
Example of form class field:
->add('housing', EntityType::class,
array(
'class' => 'TruckeeProjectmanaBundle:Housing',
'choice_label' => 'housing',
'placeholder' => '',
'attr' => (in_array('Housing', $options['disabledOptions']) ? ['disabled' => 'disabled'] : []),
'label' => 'Housing: ',
'query_builder' => function (EntityRepository $er) use ($options) {
if (false === in_array('Housing', $options['disabledOptions'])) {
return $er->createQueryBuilder('alias')
->orderBy('alias.housing', 'ASC')
->where('alias.enabled=1');
} else {
return $er->createQueryBuilder('alias')
->orderBy('alias.housing', 'ASC');
}
},
))
...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Truckee\ProjectmanaBundle\Entity\Household',
'required' => false,
'disabledOptions' => [],
));
}
Jquery to remove disabled attribute:
$("input[type=Submit]").click(function () {
$("input").removeAttr("disabled");
$("select").removeAttr("disabled");
});
Example of template & jquery for ManyToMany relationship:
<div id="household_options" style="display:none;">{{ metadata }}</div>
jquery:
if (0 < $("#household_options").length) {
var house_options = JSON.parse($("#household_options").text());
$.each(house_options, function (index, item) {
$.each(item, function (k, v) {
var formAttr = 'household_' + index + '_' + v.id;
$("#" + formAttr).attr('disabled', 'disabled');
});
});
}
I am using the MultiForm module to submit a long form with SilverStripe. The logic for this form is in 'CampaignBriefForm.php' whereas the gridfield CMS field is being added in 'CampaignBriefPage.php'. I have a Data Object for a CampaignBriefLead which is what the form creates.
Campaign Brief Page
private static $has_many = array(
'CampaignBriefLeads' => 'CampaignBriefLead'
);
public function CampaignBriefForm() {
return new CampaignBriefForm($this, 'CampaignBriefForm');
}
Campaign Brief Lead (DO)
private static $has_one = array( "Page" => "CampaignBriefPage" );
As you can see the Campaign Brief page has the correct relationship with the Data Object and also you can see the the form itself (done in a sepearate file) is correctly returning (as it's being saved in the DB). For some reason however, the gridfield will not show me what is in the database for that Data Object. The grid field code is as follows.
$fields = parent::getCMSFields();
$contactConfig = GridFieldConfig_RelationEditor::create();
$contactConfig->getComponentByType('GridFieldDataColumns')->setDisplayFields(
array(
'CompanyName' => 'Company Name',
'StartDate' => 'Start Date',
'Duration' => 'Duration',
'WebsiteURL' => 'Website',
'Budget' => 'Budget'
));
$contactGrid = new GridField(
'CampaignBrief',
'Campaign Enquiries',
$this->CampaignBriefLeads(),
$contactConfig
);
$fields->addFieldToTab("Root.Enquiries", $contactGrid);
To me this all looks correct and should work but for some reason it is not working.
Note
The link existing option on the gridfield allows me to link one of the entries from the DO with the gridfield weirdly?? So it saves one entry but I have to do it manually, this tells me it can see the DB but won't pull for some reason.
For reviewing reasons, here is the code for the multiform where the campaign brief lead is actually saved to the DB after the form is submitted.
public function finish($data, $form) {
parent::finish($data, $form);
$steps = DataObject::get(
'MultiFormStep',
"SessionID = {$this->session->ID}"
);
$enquiry = new CampaignBriefLead();
foreach($steps as $step) {
$data = $step->loadData();
foreach($data as $key => $value) {
if($key == 'url' || $key == 'MultiFormSessionID' || $key == 'action_finish') {
continue;
}
if(isset($data[$key])) {
$enquiry->$key = $data[$key];
error_log($data[$key]);
}
}
}
$enquiry->write();
$this->controller->redirect('/campaign-brief/');
}
If you need anything more let me know. Thanks.
I would take a guess that the CampaignBriefLead PageID is not being set on your form submission.
Check the CampaignBriefLead table in your database and check the PageID column. If it is blank, null or 0 for each row then it is not being set.
One way to fix this problem for any new submission is to set the PageID for the $enquiry:
public function finish($data, $form) {
// ...
$enquiry = new CampaignBriefLead();
if ($campaignBriefPage = CampaignBriefPage::get()->first()) {
$enquiry->PageID = $campaignBriefPage->ID;
}
// ...
}
For the existing entries you will need to update the entries to have the correct PageID.
I creter js file and add tbar add button when click one blnak row add in grid
in movies controller file i write
function ext_item($id = null) {
if(!empty($this->data)) {
if($this->Movie->save($this->data))
{
$this->set('success','true');
$this->data = array();
return;
}
else {
$this->set('success',"false");
return;
}
}
}
how to pass this js data ?
how to insert data in database?
in controller file
function create() {
$newData = json_decode($this->params['form'], true); // turn the incomin json into an array
$this->data = array(
'Movie' => array(
'date_' => $newData['date_'],
'notes' => $newData['notes'],
'asset_id' => $newData['asset_id'],
'maint_picture' => $newData['maint_picture'],
'maint_condition1' => $newData['maint_condition1'],
'maint_condition2' => $newData['maint_condition2'],
'maint_condition3' => $newData['maint_condition3'],
'maint_condition4' => $newData['maint_condition4'],
)
);
if ($this->Movie->save($this->data))
{
$data['success'] = true;
} else {
$data['success'] = false;
}
$this->set('data', $data);
//$this->layout = 'ajax';
return $this->render(null, null, '/movies/ext_item');
}
then in js file
var proxy = new Ext.data.HttpProxy({
api: {
// these will map to cakephp controller actions
create: { url: 'movies_controller/create', method: 'POST' },
// read: { url: '/movies_controller/index', method: 'POST' },
//update: { url: '/movies_controller/update', method: 'POST' },
destroy: { url: 'movies_controller/destroy', method: 'POST' }
}
});
and for add row in grid
tbar: [{
text: 'Add Movie',
icon: 'images/table_add.png',
cls: 'x-btn-text-icon',
handler: function() {
grid.getStore().insert(0, new Movie({
id: 0,
notes: 'New Movie',
asset: ''
}));
rowEditor.startEditing(0, true);
}
}]
What wrong with this. it's not insert data in database.
What you want to do is add to the grid using ExtJS. The store that is attached to your grid (if you follow my answer to your last question) will handle talking to the server.
In ExtJS, the button in your toolbar to add a row to your grid should have a handler.
var toolbar = Ext.Toolbar({
// config options
handler: function() {
// in your handler you need to create a new record and insert it into your store
// if you followed my answer to your last question, you'll have setup a store with proxy, jsonreader, and jsonwriter.
// get the store component from Ext
var store = Ext.getCmp('idOfYourStore'),
NewRecord = Ext.data.Record.create(['name', 'genre', 'length']); // this array of column names should match the fields you specified for your JsonReader's fields
// now that you have your store component, and your new blank record. you can fill it in and add it to the store
var record = new NewRecord({
name: 'Name of Movie',
genre: 'Genre of Movie',
length: '1:25:22'
});
store.add(record);
store.commitChanges();
}
});
After calling add (if autosave is set to true on your store) it will automatically call the url to your cakephp application that you setup in your proxy's api under 'create'. It will send the data of this new record to that action.
So if you set up you're create proxy to point to /movies/create than inside of your MoviesController you want to setup a create() action.
Inside of the create action, you'll want to check $this->params['form'] for the incoming data from ExtJS.
function create() {
$newData = json_decode($this->params['form'], true); // turn the incomin json into an array
$this->data = array(
'Movie' => array(
'name' => $newData['name'],
'genre' => $newData['genre'],
'length' => $newData['length']
)
);
if ($this->Movie->save($this->data)) {
$data['success'] = true;
} else {
$data['success'] = false;
}
return json_encode($data);
}
After ExtJs makes the post to PHP it expects a json object back with a 'success' key in the root of the object with true, or false. You need this in json, so you can't simply just use $this->set and send it to your view. In this case I'm returning the json_encoding string.
In reality what you should do, is include the Js helper in your app_controller. Then create an element named ajaxreturn. /views/elements/ajaxreturn.ctp would contain one line.
<?php echo $this->Js->object($data) ?>
Object is responsible for turn $data into a json object. It's used instead of json_encode because PHP4 didn't have support for json_encode.
now that you have this element, in your controller you can rewrite it like so...
function create() {
$newData = json_decode($this->params['form'], true); // turn the incomin json into an array
$this->data = array(
'Movie' => array(
'name' => $newData['name'],
'genre' => $newData['genre'],
'length' => $newData['length']
)
);
if ($this->Movie->save($this->data)) {
$data['success'] = true;
} else {
$data['success'] = false;
}
$this->set('data', $data);
$this->layout = 'ajax';
return $this->render(null, null, '/elements/ajaxreturn');
}
You want to return the json string and ONLY the json string. No layout, no html, nothing but the string it will throw an error.
Once you do this, your store will know whether the call was successful, if so it will stick a row in your grid. If not, it will delete the temp. row it put in your grid.
I'm not sure I understanding what you're asking for.
RequestHandler is how cake enables handling javascript/ajax requests:
http://book.cakephp.org/view/1291/Request-Handling