I am trying out a small JavaScript library, SnackJS and am doing pretty well. But I've hit a wall, and can't seem to figure this one out:
Snack:
<script type="text/javascript">
snack.ready(function () {
var parameters = {
node: document.body,
event: 'change',
delegate: function (node) {
return node.getElementsByClassName("qty")
}
}
snack.listener(parameters, postToOtherPage);
function postToOtherPage() {
var options = {
method: 'post',
url: '/InlineEditing',
data: {
qty: 5,
id: "hi"
}
}
}
});
</script>
My question is, on the change event of an input element, how do I post the id of the element, along with that element's value (qty) to another page?
I did look through the documentation, but I can't quite figure it out.
You're missing a
snack.request(options, callback);
call. A part from that, your code looks fine.. what's wrong with it?
Update
oh, I see you're not retrieving the id from the element.. from the docs: the first argument to event callback is the node which fired the event, so:
snack.ready(function () {
var parameters = {
node: document.body,
event: 'change',
delegate: function (node) {
return node.getElementsByClassName("qty")
}
}
snack.listener(parameters, postToOtherPage);
function postToOtherPage(event) {
var options = {
method: 'post',
url: '/InlineEditing',
data: {
qty: 5,
id: this.id
}
}
snack.request(options, function(){
// do something with response..
});
}
});
should work fine..
Update
Nope, sorry, further reading the docs I found out they're using callback.apply(this, [event]), as usual.. updated code above.
By the way, I don't see the point in using this kind of micro-libraries instead of well-established libraries such as jQuery/Zepto, since the pros of the micro-libaries in terms of size are not worth IMO the disadvantages.
Consider that "larger" libaries:
have a lot more features: what about the day you'll decide to extend your application functionality more?
have a larger community/commercial-based support: books, reference, guides, ...
are more likely to have already solved problems/issues that are still there in micro libraries. Just think of the hundreds of cross-browser compatibility hacks...
However, this one is just my opinion, just take it as my personal advice.
Related
I am very new in javascript/jQuery so please bear with me if my question will be too easy for you and too difficult for me.
This is from a function, I just don't post the complete codes since it will be too long.
And I have another function which also have an ajax and I want to pass get the ID of the <a> tag:
function someName() {
jQuery.ajax({
type: 'POST',
url: 'thisisprivate.aspx',
data: {
action: 'MyAction',
word: 'Wednesday',
count: '4',
page: '1'
},
success: function(data) {
var json = jQuery.parseJSON(data);
var htmlInfo = '';
for (i = 0; i < json.length; i++) {
var htmlCode = '';
htmlInfo = htmlInfo + htmlCode;
}
jQuery('#WMVideoxx').html(htmlInfo);
}
});
}
and
function VideoDiv() {
jQuery.ajax({
type: 'POST',
url: 'thisisprivate.aspx',
data: {
action: 'actionNameHere',
idorname: id //I Want to pass the ID here
});
}
What you are doing is:
jQuery('a').click(function() {
VideoDiv(jQuery(this).attr('id'));
});
This will not work because of the nature of <a> tag being dynamically generated and the event doesn't get registered. Consider delegating the event (see Understanding Event Delegation for more information):
jQuery(document).on("click", 'a', function() {
VideoDiv(jQuery(this).attr('id'));
});
The above code works, but will delegate for all the <a> inside the document. Instead, add a class or something that uniquely identifies that. And call it this way:
jQuery(document).on("click", 'a.class', function() {
VideoDiv(jQuery(this).attr('id'));
});
Another thing about the above delegation of code is, it is better to use a closest static parent instead of document. Since I don't know the HTML structure, I have used document. :)
Also, as Ismael Miguel says, it is better to get the id using this.id:
jQuery(".static-parent").on("click", '.class', function () {
VideoDiv(this.id);
});
The above would be the best code.
Also, it has been pointed out again, for better performance, you may replace the code with:
setTimeout(
(function () {
VideoDiv(this.id);
}).bind(this), 10
);
This will let jQuery handle the next even handler, and will execute this code on the next 10ms (when available).
use onclick="function();" with your anchor and pass arguments that you want in your function
Your htmlcode should be like this
Your VideoDiv function
function VideoDiv(id)
{
//your ajax goes here
}
Try this : you can put onclick call to a tag while creating it and pass this object which is nothing but the a tag element, see below code
var htmlCode = '';
Now make following changes in your javascript function
function VideoDiv(anchor)
{
jQuery.ajax({
type: 'POST',
url: 'thisisprivate.aspx',
data: {
action: 'actionNameHere',
idorname: anchor.id //pass id here from anchor object
}
});
}
NOTE: your data attribute in above ajax call is incomplete, please correct it.
I've been trying to figure out this issue with my website for a while now--I have a bunch of "stars" a user can click on.
clicking on a star loads a file into a div with information regarding that star. It also loads a button for the players to click and "Take over" the planet. That all is working well and fine, however--I've recently discovered an issue that I'm not quite sure how to handle.
IF a player clicks on multiple stars before reloading the page for whatever reason--when the click to attack/whatever the star--it'll send multiple requests across the server. I at first thought this was something in my coding that was sending all information regarding all the stars, however I've come to realize that it's only the stars that the player has clicked on.
Now--Here is the code:
$.ajaxSetup ({
// Disable caching of AJAX responses
cache: false
});
function loadStatus()
{
$.ajax(
{
url:'world1.php', error: function () { }, dataType:'json',
success: function(data)
{
denial = false;
$('#credits').html(data.credits);
$('#fuelleft').html(data.fuel);
$('#energyleft').html(data.energy);
}
});
}
function currentStarMapURL(URL)
{
$('#starmap').load(URL, {},
function()
{
$('#loader').hide();
fullStarInformation(URL);
starInformation();
setInterval(function() { $('.unknown').effect("highlight",{color:"#800000"}, 1500)});
return false;
}
);
}
/*
purhcase upgrades
*/
/*
Retriever Better Star Info
*/
function fullStarInformation()
{
$(".star").click(
function()
{
$('#planet-bar').empty();
val = this.id;
url = "planet.php?sid="+val;
$('#planet-bar').load(url, {'sid':val},
function()
{
colony(url);
}
);
}
);
}
function colony(url)
{
$('#planet-bar').on("click", "button",
function() {
event.preventDefault();
name = 0;
$(this).hide();
name = $(this).attr('sid');
$.post('purchase.php?mode=planet', {sid: name},
function ()
{
$('#planet-bar').load(url, {}, function () { currentStarMapURL(URL2); })
}
);
$(this).prop('disabled', true);
});
}
I figured at first that the issue was a caching issue, so I added the $.ajaxSetup to the first line, but that didn't seem to change anything.
Then I figured, maybe it's the way the code was being called--I originally had two seperate functions; one for attack, one for colonizing. both of which were being called in the fullStarInformation function, So I moved it all down to one function, i'm still getting the issue.
AFAIK, right now, i may have to rewrite this entire block of code so that the colony function and the starInformation function are separate and not acting upon one another. But I wanted to get a second, third maybe even fourth set of eyes on the code before I go about doing that.
If you are getting multiple ajax calls, chances are you are setting up multiple event handlers.
Just quickly glancing through the code, I would think you should change
function colony(url)
{
$('#planet-bar').on("click", "button", function() { ... } );
To
function colony(url)
{
$('#planet-bar').off("click", "button"); //unbind old event handlers
$('#planet-bar').on("click", "button", function() { ... } );
I have a page http://www.projectdemocracy.in/ where some elements are dynamically added (example - CSS class ".fyre-comment-count" showing "X Comment").
I wanted to modify the text once page is loaded.
I was able to change the text using console of jQuery
$(".fyre-comment-count").html($(".fyre-comment-count").text().split(" ")[0]+" Conversations");
When I type the same in my page, it doesn't work.
I also tried $(document).ready(function(){}); but no luck (same with document.ajaxSuccess).
Similarly, document.on would be working only with 'click' events but I want it to be done by default.
$(document).on('click', '.fyre-comment-article', function() {
//Code
});
Does it have any 'load' type event in document.on?
What should I do to accomplish this?
Thanks,
I analyzed your web page and saw the following code:
var articleId = fyre.conv.load.makeArticleId(null);
fyre.conv.load({}, [{
el: 'livefyre-comments',
network: "livefyre.com",
siteId: "351251",
articleId: articleId,
signed: false,
collectionMeta: {
articleId: articleId,
url: "http://projectdemocracy.in",//fyre.conv.load.makeCollectionUrl(),
}
}], function() {});
It seems like the 3rd argument of fyre.conv.load method is a callback function that will be executed when all elements are generated.
So put your code inside this function. It will be like this:
...
}], function() {
console.log('callback');
$(".fyre-comment-count").html($(".fyre-comment-count").text().split(" ")[0]+" Conversations");
});
Hope this helps!
EDIT
If it still doesn't work it may be because livefyre runs this callback before DOM elements are being created. The workaround is to put $(".fyre-comment-count").html(...); inside setTimeout with minimal delay:
...
}], function() {
setTimeout(function() {
$(".fyre-comment-count").html($(".fyre-comment-count").text().split(" ")[0]+" Conversations");
}, 10); //minimal delay. wait till livefyre generates all needed elements
});
EDIT 2
This is another variant how to make it work:
...
}], function(widget) {
widget.on('commentCountUpdated', function() {
setTimeout(function() {
$(".fyre-comment-count").html($(".fyre-comment-count").text().split(" ")[0]+" Conversations");
}, 10);
});
});
This widget has a commentCountUpdated event, so you have to subscribe on it, and every time the comments number is changing, your callback will be executed
By the way, commentCountUpdated callback recieves a single argument - the number of comments, so you can rewrite your code as follows:
}], function(widget) {
widget.on('commentCountUpdated', function(commentsNum) {
setTimeout(function() {
$(".fyre-comment-count").html(commentsNum + " Conversations");
}, 10);
});
});
jQuery has a on load event, if this is what you are looking for:
$(window).load(function(){ ... });
I have already implemented some AJAX pagination in my Rails app by using the example code for the will_paginate plugin--which is apparently using Prototype.
But if I wanted to switch to using jQuery for future additions, I really don't want to have the Prototype stuff sitting around too (yes, I know it's possible). I haven't written a lick of JavaScript in years, let alone looked into Prototype and jQuery... so I could use some help converting this bit into jQuery-compatible syntax:
document.observe("dom:loaded", function() {
// the element in which we will observe all clicks and capture
// ones originating from pagination links
var container = $(document.body)
if (container) {
var img = new Image
img.src = '/images/spinner.gif'
function createSpinner() {
return new Element('img', { src: img.src, 'class': 'spinner' })
}
container.observe('click', function(e) {
var el = e.element()
if (el.match('.pagination a')) {
el.up('.pagination').insert(createSpinner())
new Ajax.Request(el.href, { method: 'get' })
e.stop()
}
})
}
})
Thanks in advance!
Edit: Nick Craver's answer got me 90% of the way there, so I just had to pick up enough jQuery to make the HTML element substitution. In place of the line where Nick had $.get($(this).attr("href"));, put this line:
$.get(this.href, null, function(data){ $(this).html(data); }, 'html');
You can shorten this down a bit in jQuery to:
$(function() {
$('.pagination a').live('click', function(e) {
$(this).parent('.pagination')
.append("<img src='/images/spinner.gif' class='spinner' />");
$.get($(this).attr("href"));
return false;
});
});
I'm not entirely sure about new Ajax.Request(el.href, { method: 'get' }) though, is this a script being requested? It looks like nothing's being done with the content after return.
I am using Rails and jQuery, making an ajax call initiated by clicking a link. I setup my application.js file to look like the one proposed here and it works great. The problem I'm having is how can I use $(this) in my say.. update.js.erb file to represent the link I clicked? I don't want to have to assign an ID to every one, then recompile that id in the callback script..
EDIT
To give a simple example of something similar to what I'm trying to do (and much easier to explain): If a user clicks on a link, that deletes that element from a list, the controller would handle the callback, and the callback (which is in question here) would delete the element I clicked on, so in the callback delete.js.erb would just say $(this).fadeOut(); This is why I want to use $(this) so that I dont have to assign an ID to every element (which would be the end of the world, just more verbose markup)
application.js
jQuery.ajaxSetup({ 'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript,application/javascript,text/html")} })
function _ajax_request(url, data, callback, type, method) {
if (jQuery.isFunction(data)) {
callback = data;
data = {};
}
return jQuery.ajax({
type: method,
url: url,
data: data,
success: callback,
dataType: type
});
}
jQuery.extend({
put: function(url, data, callback, type) {
return _ajax_request(url, data, callback, type, 'PUT');
},
delete_: function(url, data, callback, type) {
return _ajax_request(url, data, callback, type, 'DELETE');
}
});
jQuery.fn.submitWithAjax = function() {
this.unbind('submit', false);
this.submit(function() {
$.post(this.action, $(this).serialize(), null, "script");
return false;
})
return this;
};
// Send data via get if <acronym title="JavaScript">JS</acronym> enabled
jQuery.fn.getWithAjax = function() {
this.unbind('click', false);
this.click(function() {
$.get($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
// Send data via Post if <acronym title="JavaScript">JS</acronym> enabled
jQuery.fn.postWithAjax = function() {
this.unbind('click', false);
this.click(function() {
$.post($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
jQuery.fn.putWithAjax = function() {
this.unbind('click', false);
this.click(function() {
$.put($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
jQuery.fn.deleteWithAjax = function() {
this.removeAttr('onclick');
this.unbind('click', false);
this.click(function() {
$.delete_($(this).attr("href"), $(this).serialize(), null, "script");
return false;
})
return this;
};
// This will "ajaxify" the links
function ajaxLinks(){
$('.ajaxForm').submitWithAjax();
$('a.get').getWithAjax();
$('a.post').postWithAjax();
$('a.put').putWithAjax();
$('a.delete').deleteWithAjax();
}
show.html.erb
<%= link_to 'Link Title', article_path(a, :sentiment => Article::Sentiment['Neutral']), :class => 'put' %>
The combination of the two things will call update.js.erb in rails, the code in that file is used as the callback of the ajax ($.put in this case)
update.js.erb
// user feedback
$("#notice").html('<%= flash[:notice] %>');
// update the background color
$(this OR e.target).attr("color", "red");
jQuery already handles the this issue for you with the event properties:
$("a").click(function(e){
e.preventDefault();
$("#foo").fadeIn(3000, function(){
$(e.target).text("Foo loaded");
});
});
Note how I can refer back to the main link via its event. This is the case with any events that are handled within as well. Just give them unique names, such as e2, e3, etc. No more need to constantly write yet another var item = $(this) line to keep track of this three events back.
Online Demo: http://jsbin.com/egelu3/edit
If your JS is coming from the server, there is really no way that $(this) can operate in the same context. The closest you could get would be to load some script from the server and eval it in the context of your client-side function.
I basically have an id for each of the DOM elements I need to manipulate, and refer to them within my scripts. It is occasionally ugly, but the alternatives are worse.
If your JS is coming from the server,
there is really no way that $(this)
can operate in the same context. The
closest you could get would be to load
some script from the server and eval
it in the context of your client-side
function.
Not true
I basically have an id for each of the
DOM elements I need to manipulate, and
refer to them within my scripts. It is
occasionally ugly, but the
alternatives are worse.
I don't think this is ugly.
The key to this problem is functional scoping. Let me show you what I mean. You need to create a function that is called before you send your XHR call. In your case, you're doing it with a click event, so let me show you an example tailored for you:
$( '#somelink' ).click( function( )
{
// this stores the location of the current "this" value
// into this function, and will available even after we
// end this function (and will still live while the XHR's
// callback is being executed
var theLink = this;
// fire the AJAX call
$.post
(
'some/url',
{ 'some':'data' }, // optional
function( )
{
// use theLink however you want
// it'll still be there
// also, if you're sending in callbacks
// as variables, you can safely say
hideAndStore.call( theLink, data );
// which executes callback( ), overriding
// "this" with theLink (your DOM node)
// and sending in the responseText as the
// first argument
}
);
} );
and then you could make your callback something like:
function hideAndStore( response )
{
// you can safely use "this" as the DOM node
$( this ).css( { 'display':'none' } );
// and you can do whatever you wish with the response
window.globalData = response;
}
where you'd make it do whatever you actually want it to do, haha.
For more info about functions in JavaScript that change the "this" value, check out .apply and .call at MDC
https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Function/Apply https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Function/Call
What are you doing in the javascript you are sending back? Maybe you can send back some html or json and operate on it in a callback.
$('a:clickable').bind('click', function() {
var elem = $(this);
$.ajax({
url: ...,
dataType: 'json',
success: function(data) {
// elem is still in scope
elem.addClass(data.class_to_add_to_link);
}
});
});
This cannot be accomplished, The method in which i am trying to do this makes it impossible, i cannot pass references to javascript objects through views.
Solution was to assign IDs to each item, and refer to them by that.