I'm trying to iterate over an array of elements, specified by class name. Then I want to use a function to toggle the class and change some text.
This does NOT work:
$$('.btn').forEach( setButtonLoadingStateOn, this );
setButtonLoadingStateOn = function( btn ) {
btn.toggleClassName('loading');
btn.disable();
btn.select('span span')[0].update( "please wait..." );
}
This does NOT work:
$$('.btn').each( function(btn) {
btn.addClassName('loading');
btn.disable();
btn.select('span span')[0].innerHTML = "please wait...";
});
This also does NOT work:
setButtonLoadingState( '.btn', 'start' );
setButtonLoadingState = function( btnClass, loadState ) {
btnElem = $$( btnClass );
btnElem.each(function( el ){
if ( loadState == 'start' ) {
el.addClassName( 'loading' );
el.disable();
el.select('span span')[0].innerHTML = "please wait...";
} else {
el.removeClassName( 'loading' );
el.enable();
el.select('span span')[0].innerHTML = "buy now";
}
});
}
If I console.log() the element, I get the object (or array) I'm expecting, so I don't know what's wrong.
I've also tried several SO answers, including this one: Add or remove class with prototype
In case it matters, the platform is Magento CE 1.8.0.2. How can I update these button elements using Prototype? Thanks.
~ edit ~
There are several HTML elements on the page. They all look like this:
<button type="button" title="buy now" class="button btn" onclick="productAddToCart(this)">
<span><span>Quick Buy</span></span>
</button>
Thanks so much to all who contributed. The AJAX request was returning a hyphenated key in the JSON response:
{"msg-html":"blah blah blah"}
Reading this from the response object as follows was the problem:
var ajaxResult = transport.responseText.evalJSON();
var ajaxMsg = ajaxResult.msg-html;
Hyphens are not allowed in JSON keys, instead the object needs to be accessed as follows:
var ajaxMsg = ajaxResult["msg-html"];
... or remove the hyphens! Thanks again to all.
Full credit to this dude/dudette: http://developer.appcelerator.com/question/120227/parsing-json-with-hyphenated-key-names
Related
field: 'Status' ,
width: '70px' ,
template: "#if(Status == 'On Request') {#<div class='redAndBold'>#:Status</div>#}#"
I have a kendo UI grid where the "Status" is being filled in from the javascript file. The Status in the model can be "On Request", and what I want is: if it is "On Request", add a class to it, "redAndBold". The syntax in this particular example gives a "user is not defined" error.
Could anyone give me some pointers on how to correctly do this?
The kendo.templates depend on #=fieldName# or #:fieldName#. In the current case, there is a missing closing "#" after 'Status'. The templates are evaluated with the value of the field when bound to a data item during initialization. For executing JavaScript logic use only "#JS logic goes here#". Further information can be found here Kendo UI templates.
To avoid confusion of the template syntax, plain JavaScript function can be used instead:
template: "#=templateFunc(data)#"
// JS hander
function templateFunc(dataItem){
if(dataItem.Status== 'On Request') {
return "<div class='redAndBold'>"+dataItem.Status+"</div>";
} else{
return dataItem.Status;
}
}
I think you are missing a # after Status. When you inject the value of a variable it needs a # before and after. If you split the template code over several lines whilst you write it, it can be easier to get it right.
#if(Status == 'On Request') {#
<div class='redAndBold'>
#:Status#
</div>
#}#
A good check is to count the number of # symbols in your template. It should always be an even number.
As many people pointed out, you're missing a pound sign. I would like to point out that you can set the template as a function that returns a string. I generally do this because there are nuances with the string template such as escaping pound signs among other things:
field: 'Status',
width: '70px',
template: function(dataItem) {
var div = $('<div />');
if (dataItem.Status === 'On Request') {
div.addClass('redAndBold');
}
return div.prop('outerHTML');
}
Just use function for a template :
}, {
field: "TrackingNumber",
title: "#T("Admin.Orders.Shipments.TrackingNumber")",
}, {
field: "ShippingMethodName",
title: "#T("Admin.Orders.Shipments.ShippingMethodName")",
template:function(dataItem) {
var template;
var ShippingMethodPluginName = dataItem.ShippingMethodPluginName;
var IsReferanceActive = dataItem.IsReferanceActive;
var ShippingMethodName = dataItem.ShippingMethodName;
var CargoReferanceNo = dataItem.CargoReferanceNo;
var ShipmentStatusId = dataItem.ShipmentStatusId;
if (ShipmentStatusId == 7) {
return "<div align='center'><label class='label-control'><b style='color:red'>Sipariş İptal Edildi<b></label></div>";
} else {
if (ShippingMethodPluginName == "Shipping.ArasCargo" || ShippingMethodPluginName == "Shipping.ArasCargoMP") {
template =
"<div align='center'><img src = '/content/images/aras-kargo-logo.png' width = '80' height = '40'/> <label class='label-control'><b>Delopi Aras Kargo Kodu<b></label>";
if (IsReferanceActive) {
template =
template +
"<label class='label-control'><b style='color:red; font-size:20px'>"+CargoReferanceNo+"<b></label></div>";
}
return template;
}
In my application I have a form in controller/index that consists out of 3 select boxes. When all three boxes have a value selected I need to show additional html and extra form options in the same view based on those select values. The obvious solution seems to make an ajax call to another action that handles the database operation and creates a view and loading that view into the controller/index.phtml
I have been able to load a view of another action in the index.phtml by using:
$('#select').change(function() {
event.preventDefault();
var id = $(this).attr('id');
$('#results').show();
$('#results').load('/controller/index/' + $(this).attr('value'));
return false;
});
However I need to pass the variables of all three select boxes and for that I alternatively used:
$('#select1').change(function() {
var select1 = $('#select1').val();
var select2 = $('#select2').val();
var select3 = $('#select3').val();
$.ajax({
type: 'POST',
dataType: 'json',
url: '/controller/index/',
data: { select1: select1, select2: select2, select3: select3},
success: function(result){
var return1 = result.return1;
var return2 = result.return2;
}
});
});
The last method works in as far that I do see the variables passed in the headers and the response contains the view, but I cant fix it that just the content of the ajax view is placed within the index view. (Ofcourse by not using AjaxContent switching, the ajax view will load but that includes the complete layout as well.) Anything that I echo in the ajax action or ajax view do not show in the index view. Any pointer would be more than welcome
EDIT
the ajax action now looks like
$this->view->layout()->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
$select1 = $this->_request->getParam('select1');
$select2 = $this->_request->getParam('select2');
$select3 = $this->_request->getParam('select3');
// DO THE OTHER STUFF AND LOGIC HERE
$results = array(
'return1' => 'value1',
'return2' => 'value2'
);
$this->_response->setBody(json_encode($results));
and the controller init
public function init() {
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('ajax', 'json')->initContext();
}
So everything works, I can see the returned values in the response by using developer tool (network) in my browser, however I just do not know how I can use this to "update" the view
You can do two things:
You can enable the layout of the action you are calling via ajax. See you have disabled layout so even if the view phtml file of the ajax action contains something, it won't show. You can enable layout, use text/html dataType instead of json and show the returned HTML somewhere.
Or, in the success event of the ajax call, write javascript codes to update DOM.
Thanks #Salman for your suggestions as they lead me in the right direction and I managed to solve the problem.
I managed to pass multiple parameters with the ajax .load() call by passing them as get parameters.
The results of the ajaxAction could then be formatted in the ajax.ajax.phtml view and were consecutively
shown within the #results div that resides in the index.phtml where the select boxes are.
controller/index.phtml
<div id="results" style="display:block;">Select all three values</div>
IndexController init and ajaxAction
public function init() {
$ajaxContext = $this->_helper->getHelper('AjaxContext');
$ajaxContext->addActionContext('ajax', 'html')->initContext('html');
}
public function ajaxAction() {
$select1 = $this->_request->getQuery('select1');
$select2 = $this->_request->getQuery('select2');
$select3 = $this->_request->getQuery('select3');
$form = new Application_Form();
// Database operations and logic
$this->view->form = $form;
$this->view->array = $somearray;
}
}
jquery script in index.phtml
$(document).ready(function(){
$('.selector').change(function() {
var select1 = $('#select1').val();
var select2 = $('#select2').val();
var select3 = $('#select3').val();
if ( select1 && select2 && select3) {
$('#results').show();
$('#results').load('/controller/ajax?select1=' + select1 + '&select2=' + select2 + '&select3=' + select3);
}
});
});
controller/ajax.ajax.phtml
<?php if ( $this->array ) : ?>
<?php echo( $this->form ); ?>
<?php else: ?>
Nothing found for selected values
<?php endif ?>
Thanks in advance for your help guys.
I consider myself pretty well-versed in jQuery but as I was helping my sister with her Prototype homework, this frustrated the crap out of me. She couldn't solve it in time so that's moot but for my sanity's sake, I hope you can tell me what's going on.
We were simply creating a netflix-style queue with add, reorder and delete through AJAX. The items were in a UL and had a delete link inside each LI with unique IDs to be used for deletion. Please don't fixate on why we were using text files to save data, etc. - her professor made that impractical choice a requirement, along with a few others...
JS:
function softRefresh() {
$$('.delete').invoke('observe','click',function() { taskDelete(this.id); });
Sortable.create("taskList", { onUpdate: function(list){ saveOrder(list); } });
}
function taskDelete(a) {
var tempArr = a.split('-');
var keyToDelete = tempArr[1];
var output;
var ajaxRequest = new Ajax.Request("todolist.php",
{
method: "post",
parameters: {
action: 'delete',
id: keyToDelete
},
onSuccess: function(response) {
$('taskList').update(response.responseText);
softRefresh();
}
});
}
PHP for the 'delete' action:
$jsonOutput = file_get_contents($myFile);
$fetchedArr = json_decode($jsonOutput);
$newArr = array();
foreach($fetchedArr as $key => $task) {
if(($key != $_POST['id'])) {
array_push($newArr, $task);
}
}
$jsonOutput = json_encode($newArr);
file_put_contents($myFile, $jsonOutput);
$output = '';
foreach($newArr as $key => $task) {
$output .= '<li id="list_'.$key.'">';
$output .= $task;
$output .= 'X';
$output .= '</li>';
}
echo $output;
The problem was that if I deleted, say, the 2nd item, all the following items would delete as well. Through firebug console I found out that this is because when you click any link of that class ('delete') all the following listeners fire, and keeps deleting the 2nd item off the new list. Can you tell me why and how I can set it so it only fires off the link you click? It drove me nuts all day. I'm used to having .click() on jQuery... much hatred for Prototype at the moment.
Thanks again!
JS:
You shouldn't need the softRefresh if you set the events well. Likewise, the <ul> element is never disposed nor replaced so only one Sortable should be necessary, there is no need to remake that each time.
Event.on('taskList', 'click', '.delete', taskDelete);
Sortable.create("taskList", { onUpdate: saveOrder });
function taskDelete(event, element) {
var id = element.id;
var tempArr = id.split('-');
var keyToDelete = tempArr[1];
new Ajax.Updater({success: 'taskList'}, "todolist.php",
{parameters: {
action: 'delete',
id: keyToDelete
}}
);
}
(Ajax objects in prototype are already POSTs so that doesn't need to be specified. Use of an Updater is neater too. There is little point in wrapping a function call in an anonymous function, it may be the jQuery way but it isn't adding any functionality, javascript functions are objects so use them as such.)
PHP:
I felt $newArr was a waste of a loop and some memory so here is a shorter way.
$jsonOutput = file_get_contents($myFile);
$fetchedArr = json_decode($jsonOutput);
unset($fetchArr[$_POST['id']]);
// Keys are preserved here, if you need to reorder use:
// $fetchedArr = array_values($fetchArr);
$jsonOutput = json_encode($fetchedArr);
file_put_contents($myFile, $jsonOutput);
foreach($fetchedArr as $key => $task) {
echo '<li id="list_'.$key.'">';
echo $task;
echo 'X';
echo '</li>';
}
This is a follow-up to AJAX Call Does Not Trigger Action Method When Decorated With CanvasAuthorize
So I found the following links and it seems that this is a common problem:
http://facebooksdk.codeplex.com/discussions/251878
http://facebooksdk.codeplex.com/discussions/250820
I tried to follow the advice by prabir but I couldn't get it to work...
Here's my setup:
I have the following snippet in the page where the button that triggers the whole post to facebook is located:
#if (!string.IsNullOrEmpty(Request.Params["signed_request"]))
{
<input type="hidden" id="signedReq" value="#Request.Params["signed_request"]" />
}
And then I have this snippet (inside a script tag inside the same page):
var signedRequest = $('#signedReq').val();
$('.facebookIcon').click(function () {
var thisItem = $(this).parent().parent();
var msg = thisItem.find('.compItemDescription').text();
var title = thisItem.find('.compareItemTitle').text();
var itemLink = thisItem.find('.compareItemTitle').attr('href');
var img = thisItem.find('img').first().attr('src');
postOnFacebook(msg, itemLink, img, title, signedRequest);
});
And finally, inside an external js file I have the following function:
/*Facebook post item to wall*/
function postOnFacebook(msg, itemLink, pic, itemTitle, signedReq) {
console.log(signedReq);
var siteUrl = 'http://www.localhost:2732';
$.ajax({
url: '/Facebook/PostItem',
data: {
'message': msg,
'link': siteUrl + itemLink,
'picture': siteUrl + pic,
'name' : itemTitle,
'signed_request': signedReq
},
type: 'get',
success: function(data) {
if(data.result == "success") {
alert("item was posted on facebook");
}
}
});
}
But signedReq is always undefined. And I'm not really sure I should be passing the 'signed_request' field inside the data object. Any thoughts?
Make sure you hidden input field is being populated.
Also, when you try to pull the ID of the input field via JQuery, you might not be referencing the proper element since .NET butcher's ID's of anything that's run on the server.
When I use the hidden input field trick, I set the jquery value like so:
var signedRequest = $('#<%=signedReq.ClientID %>').val();
This way, I'm getting the identifier that .NET is giving to the HTML element.
Hope that helps.
Just a guess - in your hidden field: id="signed_request" instead of id="signedReq"
i am trying to aggregate form elements into object and then send it via ajax here is the code that i start using but i cant figure out how to do the rest
$('.jcart').live('submit', function() {
});
Update 1:
html form
http://pasite.org/code/572
Update 2:
I have successfully submit the form using ajax but it still refreshes the page after submiting
this what i did
function adding(form){
$( "form.jcart" ).livequery('submit', function() {var b=$(this).find('input[name=<?php echo $jcart['item_id']?>]').val();var c=$(this).find('input[name=<?php echo $jcart['item_price']?>]').val();var d=$(this).find('input[name=<?php echo $jcart['item_name']?>]').val();var e=$(this).find('input[name=<?php echo $jcart['item_qty']?>]').val();var f=$(this).find('input[name=<?php echo $jcart['item_add']?>]').val();$.post('<?php echo $jcart['path'];?>jcart-relay.php',{"<?php echo $jcart['item_id']?>":b,"<?php echo $jcart['item_price']?>":c,"<?php echo $jcart['item_name']?>":d,"<?php echo $jcart['item_qty']?>":e,"<?php echo $jcart['item_add']?>":f}
});
return false;
}
jQuery has a method called .serialize() that can take all the form elements and put them into an array for just what you are trying to do. Without seeing your html, we really can't tell you much more though.
http://api.jquery.com/serialize/
Something like this might work:
$('.jcart').submit(function() {
$.ajax({
url : form.php,
type : "POST",
data : $(this).serialize(),
});
});
Obviously it would need a little more for full functionality, but that should get you started.
Depending on how many of the values you need (and whether you have things like radio buttons) you can start with the :input selector to grab the elements. Assuming .jcart is your form or container, something like this:
var data = {};
$('.jcart').find(':input').each(function (i, field) {
if ($(field).is('input:checkbox') {
if (field.checked) {
data[field.name] = true;
} else {
data[field.name] = false;
}
} else {
data[field.name] = $(field).val();
}
});
That should get you started.