Zend forms working with ajax/javascript onchange event - javascript

I am writing a code to use onchange in my application this is my code so far
.Phtml
<script type="text/javascript">
function submit()
{
$id = intval($_GET['id']);
$satellite = intval($_GET['satellite_id']);
if ($id == 0)
{
echo "Please select a Region";
}
else
{
$query = "select * from satellites where region_id = '".$id."'";
$query = mysql_query($query);
echo "<select name='satellite_id'><option value=''>-- select one --</option>";
while ($row = mysql_fetch_assoc($query))
{
echo "<option value='".$row['satellite_id']."'".($row['satellite_id']==$satellite?" selected":"").">".$row['satellite_name']."</option>";
}
echo "</select>";
//DisplayFormRow ("Satellite", FormDropDownBox ("satellite_id", $SatelliteARY, $Result['satellite_id']));
}
}
</script
//zend code Form
$region_name = new Zend_Form_Element_Select('region_name');
$region_name->setAttribs(array('style' => 'width: 150px;'));
$region_name ->setLabel('Region')
->onchange('this.form.submit();') //tried this code ->onchange('javascript:submit();')
->addMultiOption('--Select One--', '--Select One--');
$mdlRegions = new Model_Regions();
$regions = $mdlRegions->getRegions();
foreach ($regions as $region)
{
$region_name->addMultiOption($region->region_id, $region->region_name, $region->region_short_name);
}
//model
<?php
class Model_Regions extends Zend_Db_Table_Abstract
{
protected $_name = 'regions';
//protected $_name = 'smmedetails';
public function getregion($region_id)
{
$region_id = (int)$region_id;
$row = $this->fetchRow('region_id = ' . $region_id);
if (!$row) {
throw new Exception("Could not find row $region_id");
}
return $row->toArray();
}
public function smmedetails2region($region_name)
{
$data = array(
'region_name'=> $region_name
);
return $this->insert($data);
}
public function getRegions()
{
$select = $this->select();
return $this->fetchAll($select);
}
}
//controller
public function registerAction()
{
$this->view->headScript()->appendFile('/js/ui/jquery.ui.autocomplete.js');
$form = new Form_SmmeDetails();
$this->view->form = $form;
if ($this->getRequest()->isPost()) {
$formData = $this->getRequest()->getPost();
if ($form->isValid($formData)) {
$companyname = $form->getValue('companyname');
$companytradingname = $form->getValue('companytradingname');
$region_name = $form->getValue('region_name');
$satellite_name = $form->getValue('satellite_name');
$city = $form->getValue('city');
$companyaddress = $form->getValue('companyaddress');
$addresscode = $form->getValue('addresscode');
$companypostaladdress = $form->getValue('companypostaladdress');
$postalcode = $form->getValue('postalcode');
$companyphonenumber = $form->getValue('companyphonenumber');
$companyfaxnumber = $form->getValue('companyfaxnumber');
$companycellnumber = $form->getValue('companycellnumber');
$businessemailaddress = $form->getValue('businessemailaddress');
$businesswebsite = $form->getValue('businesswebsite');
$smmedetails = new Application_Model_DbTable_SmmeDetails();
$smmeid = $smmedetails ->smmedetailsSmmeDetails($companyname, $companytradingname, $region_name, $satellite_name, $city, $companyaddress, $addresscode, $companypostaladdress, $postalcode, $companyphonenumber, $companyfaxnumber,
$companycellnumber, $businessemailaddress, $businesswebsite);
// $region = new Application_Model_DbTable_Region();
//$region ->smmedetails2region($formData, $smmedetails->smmeid);
$this->_redirect('/admin/smme/register2/smmeid/'.$smmeid);
} else {
$form->populate($formData);
}
}
}
The code is suppose to view a hidden input select, called satellite when you select a feild option from regions, the satellite should view certain options based on the region selected. In short the region selected should correspond with what the user selected. eg Province is Gauteng, so cites would be, Johannseburg,Pretoria etc. Take note the region and satellite options are called from the database table according to they names and id. The code above keeps giving me and error Message: Method onchange does not exist. Was told not to use onchange method should I be using ajax and can I use javascript and sqlquery in the view or should I call it as an action? If so how? Here is a slight picture example.
Please be of help
Thanks in advance

I'd make a few suggestions to what you have there.
Firstly, for simplicity, I'd not use the onChange function, because I don't see it in the API, plus JavaScript or jQuery written in that way can become difficult to maintain and write properly. It is a lot simpler to instead include an external JavaScript file. By doing this, you can also test and debug the JavaScript separately, as well as reuse it.
Have a look at the excellent document for onChange, and getJson. I've used these and others and they're quite straight-forward. For testing, I recommend QUnit for starters. It makes testing a breeze.
Secondly, if you're using the Zend libraries for Model_Regions and $region_name, then I'd suggest using them instead of the direct mysql calls as well. This will allow you to build a good library which you can continue to expand as needed, plus it makes composing SQL quicker and safer.
For the controller, I'd suggest a RestController with a Restful Route. Here's an excellent tutorial.
I hope this helps you out with the problem. If you need anything more, let me know.

Thanks for emailing me about this.
The way I go about this is as follows:
Firstly I set up the form, and then an action in a controller.
Lets say getmajorgroupAction()
which in that action I would then disable layout, and just get the relevent results based on the id.
Then in the view file, loop through the
so the output from that call would be
<option value="1">1</option>
<option value="2">2</option>
etc
Personally I use jquery now, whereas the post you referenced when you emailed me, I was using another method.
trying to use something like this
jQuery(document).ready(function() {
jQuery("#division").change(function () {var division = jQuery("#division").val();
jQuery("#major_group").load("/module/getmajorgroup/", {division_id: division} );});
});
Hope that makes sense.

Thanks that was useful but i found a way to do it using this formula below, but everytime I click on the first select the while still in the session the second select appears all the time, eg if a person choose the wrong selection and re tried it brings up another field instead of fixing the field. I think its in a countinous loop . heres my script
<script type="text/javascript">
$(document).ready(function() {
$("#region_name").on('change', function () {
ajaxAddField();
}
);
}
);
// Retrieve new element's html from controller
function ajaxAddField()
{
$.ajax(
{
type: "POST",
url: '<?php echo $this->baseURL()?>/admin/ajax/get-cities/city/' + encodeURIComponent($('#region_name').val()),
success: function(newElement) {
// Insert new element before the Add button
//$(this).prev().remove().end().before('#city-label');
$("#city-label").before(newElement);
}
}
);
}
</script>

Related

Pass id from the edit form in Javascript

I am trying to pass data from a form and table to edit a form, using JavaScript. The problem is that it doesn't update the form and table when I try to edit it. Can someone at least help me by giving me an example of what the code should be?
function SYS_add_product_form(){
var pullout_id=$('#tbl_pending_pullout_id').val();
$('#dialog1').remove();
$('body').append("<div id='dialog1'></div>"); /*Creates a virtual DOM <div id='dialog1'></div>*/
SYS_dialog3('#dialog1','495','950px','Create Pullout Request',function(){ });
$.post(URL+"index.php/pullout_request/loadPullOutRequestForm",{pullout_id:''}).done(function(data){
$("#dialog1").html(data).dialog("open");
});
}
function pullout_edit(x){
var pullout_id=$('#tbl_pending_pullout_id'+x).val();
SYS_dialog3('#dialog1','495','950px','Edit Pullout Request',function(){ });
$.post(URL+"index.php/pullout_request/loadPullOutRequestForm",{pullout_id:'edit'}).done(function(data){
$("#dialog1").html(data).dialog("open");
});
When adding there is no problem. But, I think maybe the problem is my elseif statement.
$pullout_id=$_POST['pullout_id'];
if ($pullout_id=='') {
$pullout_id=$this->mainmodel->getMaxId("across_pullout","pullout_id")+1;
$this->db->query("insert into across_pullout values('$pullout_id','$pullout_num','$date_requested','$user_accountid','','','','','','','0','$description','$counter','$year','1');");
for($x=0;$x<count($pid);$x++){
$pid1=$pid[$x];
$qty1=$qty[$x];
if($qty1==0){ $msg="All Quantities should be greater than zero"; }
$this->db->query("insert into across_pullout_items values('','$pullout_id','$pid1','$qty1','1');");
}
}else if($pullout_id=='edit') {
$sql .= "UPDATE `across_pullout` SET date_requested='$date_requested', `description`='$description' where pullout_num='$pullout_num' and remark='1';";
$sql .= "UPDATE across_pullout_items set pullout_qty='$pullout_qty' where remark='1';";
}
First of all, the way you use $this->db->query may cause query injection.
So I suggest you to use as follows.
$sql = "UPDATE `across_pullout` SET date_requested=?, `description`=? where pullout_num=? and remark='1'"
$this->db->query($sql, array($date_requested, $description, $pullout_num));
And $this->db->query() does not accept multiple queries.
So you need to call $this->db->query() twice to execute 2 queries.

How do I populate a list field in a model from javascript?

I have a Kendo.MVC project. The view has a model with a field of type List<>. I want to populate the List from a Javascript function. I've tried several ways, but can't get it working. Can someone explain what I'm doing wrong?
So here is my model:
public class Dashboard
{
public List<Note> ListNotes { get; set; }
}
I use the ListNotes on the view like this:
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
}
This works if I populate Model.ListNotes in the controller when the view starts...
public ActionResult DashBoard(string xsr, string vst)
{
var notes = rep.GetNotesByCompanyID(user.ResID, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
Dashboard employee = new Dashboard
{
ResID = intUser,
Type = intType,
FirstName = user.FirstName,
LastName = user.LastName,
ListNotes = listNotes
};
return View(employee);
}
... but I need to populate ListNotes in a Javascript after a user action.
Here is my javascript to make an ajax call to populate ListNotes:
function getReminders(e)
{
var userID = '#ViewBag.CurrUser';
$.ajax({
url: "/api/WoApi/GetReminders/" + userID,
dataType: "json",
type: "GET",
success: function (notes)
{
// Need to assign notes to Model.ListNotes here
}
});
}
Here's the method it calls with the ajax call. I've confirmed ListNotes does have the values I want; it is not empty.
public List<Koorsen.Models.Note> GetReminders(int id)
{
var notes = rep.GetNotesByCompanyID(id, 7, 7);
List<Koorsen.Models.Note> listNotes = new List<Koorsen.Models.Note>();
foreach (Koorsen.OpenAccess.Note note in notes)
{
Koorsen.Models.Note newNote = new Koorsen.Models.Note()
{
NoteID = note.NoteID,
CompanyID = note.CompanyID,
LocationID = note.LocationID,
NoteText = note.NoteText,
NoteType = note.NoteType,
InternalNote = note.InternalNote,
NoteDate = note.NoteDate,
Active = note.Active,
AddBy = note.AddBy,
AddDate = note.AddDate,
ModBy = note.ModBy,
ModDate = note.ModDate
};
listNotes.Add(newNote);
}
return listNotes;
}
If ListNotes was a string, I would have added a hidden field and populated it in Javascript. But that didn't work for ListNotes. I didn't get an error, but the text on the screen didn't change.
#Html.HiddenFor(x => x.ListNotes)
...
...
$("#ListNotes").val(notes);
I also tried
#Model.ListNotes = notes; // This threw an unterminated template literal error
document.getElementById('ListNotes').value = notes;
I've even tried refreshing the page after assigning the value:
window.location.reload();
and refreshing the panel bar the code is in
var panelBar = $("#IntroPanelBar").data("kendoPanelBar");
panelBar.reload();
Can someone explain how to get this to work?
I don't know if this will cloud the issue, but the reason I need to populate the model in javascript with an ajax call is because Model.ListNotes is being used in a Kendo Panel Bar control and I don't want Model.ListNotes to have a value until the user expands the panel bar.
Here's the code for the panel bar:
#{
#(Html.Kendo().PanelBar().Name("IntroPanelBar")
.Items(items =>
{
items
.Add()
.Text("View Important Notes and Messages")
.Expanded(false)
.Content(
#<text>
#RenderReminders()
</text>
);
}
)
.Events(e => e
.Expand("getReminders")
)
)
}
Here's the helper than renders the contents:
#helper RenderReminders()
{
if (Model.ListNotes.Count <= 0)
{
#Html.Raw("No Current Messages");
}
else
{
foreach (Note note in Model.ListNotes)
{
#Html.Raw(note.NoteText)
<br />
}
}
}
The panel bar and the helpers work fine if I populate Model.ListNotes in the controller and pass Model to the view. I just can't get it to populate in the javascript after the user expands the panel bar.
Perhaps this will do it for you. I will provide a small working example I believe you can easily extend to meet your needs. I would recommend writing the html by hand instead of using the helper methods such as #html.raw since #html.raw is just a tool to generate html in the end anyways. You can write html manually accomplish what the helper methods do anyway and I think it will be easier for you in this situation. If you write the html correctly it should bind to the model correctly (which means it won't be empty on your post request model) So if you modify that html using javascript correctly, it will bind to your model correctly as well.
Take a look at some of these examples to get a better idea of what I am talking about:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
So to answer your question...
You could build a hidden container to hold your list values like this (make sure this container is inside the form):
<div id="ListValues" style="display:none">
</div>
Then put the results your ajax post into a javascript variable (not shown).
Then in javascript do something like this:
$('form').off('submit'); //i do this to prevent duplicate bindings depending on how this page may be rendered futuristically as a safety precaution.
$('form').on('submit', function (e) { //on submit, modify the form data to include the information you want inside of your ListNotes
var data = getAjaxResults(); //data represents your ajax results. You can acquire and format that how you'd like I will use the following as an example format for how you could save the results as JSON data: [{NoteID ="1",CompanyID ="2"}]
let listLength = data.length;
for (let i = 0; i < listLength; i++) {
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].NoteID " value="' + data.NoteID +'" />')
$('#ListValues').append('<input type="text" name="ListNotes['+i+'].CompanyID " value="' + data.CompanyID +'" />')
//for your ajax results, do this for each field on the note object
}
})
That should do it! After you submit your form, it should automatically model bind to you ListNotes! You will be able to inpsect this in your debugger on your post controller action.

Add Dynamic JS Code on Magento Product Page

On my magento product page I need to add a dynamic JavaScript array base on display upselling products on the product page. The goal is to change the images of the upselling products when the user change the color of the main product.
To achieve my goal I need a custom JavaScript array on every product page that give me information about crossselling product and the associated product image.
What is the best way to do this?
I try this
add a observer event in my config.xml
<controller_action_layout_load_before>
<observers>
<crossselling_product_view>
<type>singleton</type>
<class>XXXXXXXX_Crossselling_Model_Observer</class>
<method>productview</method>
</crossselling_product_view>
</observers>
</controller_action_layout_load_before>
add observer to add specific JS Code
<?php
class XXXXXXXX_Crossselling_Model_Observer {
public function productview(Varien_Event_Observer $observer) {
$product = Mage::registry('current_product');
//only on product page
if (!($product instanceof Mage_Catalog_Model_Product)) {
return;
}
$controller = $observer->getAction();
$layout = $controller->getLayout();
$block = $layout->createBlock('core/text');
$block->setText(
'<script type="text/javascript">
function main_pulsestorm_hellojavascript()
{
alert("Foo");
}
main_pulsestorm_hellojavascript();
</script>'
);
$layout->getBlock('head')->append($block);
}
}
My error:
Fatal error: Call to a member function append() on a non-object
What is my problem and is it the right way to add dynamic js code?
I would probably approach this from a different angle. Since you are only interested in interacting with data and output for the upsell block, you could change the behavior of just that block by observing its output and appending your extra JavaScript. For the purposes of brevity this answer assumes that you understand the basics of Magento extensions.
Observe the core_block_abstract_to_html_after event:
etc/config.xml
<core_block_abstract_to_html_after>
<observers>
<addCustomUpsellFormat>
<class>XXXXXXXX_Crossselling_Model_Observer</class>
<method>addCustomUpsellFormat</method>
</addCustomUpsellFormat>
</observers>
</core_block_abstract_to_html_after>
Act upon instances of Mage_Catalog_Block_Product_List_Upsell by appending the output of a new block that will read their data:
Model/Observer.php
public function addCustomUpsellFormat(Varien_Event_Observer $observer)
{
/* #var Mage_Core_Block_Abstract $block */
$block = $observer->getBlock();
if ($block instanceof Mage_Catalog_Block_Product_List_Upsell) {
/* #var Varien_Object $transport */
$transport = $observer->getTransport();
// Receive the standard output for the block.
$output = $transport->getHtml();
/* #var Mage_Core_Model_Layout $layout */
$layout = $block->getLayout();
$json = $layout->createBlock('core/template')
->setTemplate('catalog/product/list/upsell_json.phtml')
->setItems($block->getItems())
->toHtml();
// Append new JSON data to block output.
$transport->setHtml($output . $json);
}
return $this;
}
Create a template that interprets the upsell data and outputs it in your desired way, in my example above I created a template that could do something like this (my example creates a new template, so it should go into the base theme):
app/design/frontend/base/default/template/catalog/product/list/upsell_json.phtml
<?php
$_json = array(); // Add data in here to convert to JSON for output.
$_items = $this->getItems();
/* #var Mage_Catalog_Model_Product $_product */
foreach ($_items as $_product) {
$_json[$_product->getId()] = array(
'image' => (string)Mage::helper('catalog/image')->init($_product, 'image')
);
}
?>
<script type="text/javascript">var upsellData = <?php echo json_encode($_json) ?>;</script>
Use
$controller = $observer->getEvent()->getAction();
instead of
$controller = $observer->getAction();

use jquery variable in # block razor

I'm strugling with a jquery script inside a cshtml page. For short my question is how to use a var inside a # statement in a cshtml page?
below an example of what I'm trying:
<select id="DefaultText">
<option value="-1">-- select --</option>
#foreach( var d in Model.DefaultTexts )
{
<option value="#d.Id" >#d.Name</option>
}
</select>
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
var text = #Model.DefaultTexts.First( t => t.Id == id );
$('#CustomProductText').val(text);
});
</script>
I can't reach the var id. It's out of scope. I've also tryed it with a for loop and a if statement. But in the if statement I get the same error: out of scope.
The full story is this:
On my page I've a dropdown list. The items to select are short names for default text parts. Based on the id or name, I want to show the default text part in a textbox.
#CustomProductText is my textbox where the content should be placed (code not posted).
I've also tryed it with #: and statement but that did not work.
What am I doing wrong or maybe its not even possible what I'm trying to do.
As an alternative I've added a action to my controller to get the text form there. Below the code:
<script type="text/javascript">
$('#DefaultText').change(function () {
var id = parseInt($('#DefaultText :selected').val());
$.post("Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
//$('#CustomProductText').val(text);
});
</script>
controller code:
[HttpPost]
public ActionResult GetDefaultText(int id)
{
using( var context = new MyContext() )
{
var text = context.DefaultText.First( d => d.Id == id ).Text;
return this.Content( text );
}
}
This doesn't work. The action doesn't get hit in debug mode.
regards,
Daniel
The $.post that is not working for you, you should prefix the url with / sign and it will be hit as expected:
$.post("/Categories/GetDefaultText", { Id: id }, function (data) {
alert(data);
});
As for the razor solution, you can't use javascript variables in the razor code as it's not a scripting language. What razor does is simply rendering the strings (be it html or javascript or anything) into the page.
To do what you want you either need to request the server to pass the text to your page or render all the texts you have in the page and then access this rendered content in your javascript.

radio button list with text option cakephp

I am new to CakePHP. I need to make a form with radio buttons and the last one is "other" where the user can type in an answer in a text box.
Is there any way FormHelper can do this that's built in?
One way I was going to do was create a radio list and a text field. When "other" is selected Javascript will show the text field. For this I don't understand how to use any other variables besides the fields in the database. How does one create a variable from a model that can be accessed from a view and the value returned for processing?
For the model I have:
class User extends AppModel {
/**
* Display field
*
* #var string
*/
public $displayField = 'title';
var $sourceOther = ' ';
var $passwordRepeat = ' ';
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = sha1(
$this->data[$this->alias]['password']);
}
// $this->data[$this->alias]['created']= CakeTime::gmt();
// $this->data[$this->alias]['updated']= CakeTime::gmt();
$this->data[$this->alias]['username']= $this->data[$this->alias]['email'];
return true;
In the view I have
echo $this->Form->input('mobilePhone',array(
'label'=>'Mobile or fixed phone with no spaces'));
echo $this->Form->input('alternatePhone');
echo $this->Form->input('leadSource', array(
'options'=>array('Google'=>'Google','OnlineAd'=>'Online Ad',
'Printed Media'=>'Printed Media','LetterDrop'=>'Letter Drop',
'Other'=>'Other (specify text)'),
'empty'=>'(choose one)'));
echo $this->Form->input($this->sourceOther);
...but it doesn't like sourceOther, the variable in the model. How do I get data from the view (the text box) into the user model so beforeSave can do something with it?
Thanks.
Thanks.
Sorted it out after reading "Cake PHP Application Development". It works for Cake 2.x and 1.2 (as used in the book).
In your view put:
echo $this->Form->input('sourceOther');
Then in the model you can access your variable with:
$this->data['User']['sourceOther'];
For example, use it to save "other" text field in beforesave:
public function beforeSave($options = array()) {
if (isset($this->data[$this->alias]['password'])) {
$this->data[$this->alias]['password'] = sha1(
$this->data[$this->alias]['password']);
}
$this->data[$this->alias]['username'] = $this->data[$this->alias]['email'];
$this->data[$this->alias]['activation'] = md5(uniqid(rand(), true));
if ($this->data[$this->alias]['leadSource'] == 'Other') {
$this->data[$this->alias]['leadSource'] =
$this->data['User']['sourceOther'];
}
return true;
}

Categories