Select from json on click - javascript

I'm trying to select a row from a json array using jquery. This is what i have:
$(document).ready(function() {
$.getJSON( "js/collectie.json", function(data) {
jsoncollectie = data;
})
$( "#collectie li" ).click(function(){
var thumb_id = $(this).data("id");
for(var i = 0; i < jsoncollectie.stoelen.length; i++){
if(jsoncollectie.stoelen[i].ref == thumb_id){
$("#detailimage").attr('src', jsoncollectie.stoelen[i].image);
$("#detailimage").attr('title', jsoncollectie.stoelen[i].title);
$("#title").html('<h4> '+jsoncollectie.stoelen[i].naam+' </h4>');
$("#secondaryimage").attr('src', jsoncollectie.stoelen[i].secondaryimage);
$("#secondaryimage").attr('title', jsoncollectie.stoelen[i].secondarytitle);
$("#description").html('<p> '+jsoncollectie.stoelen[i].description+' </p>');
}
}
});
});
Now when i click on a list item (#collectie li) the console outputs "ReferenceError: jsoncollectie is not defined". I don't know why it's doing that and i'm pretty sure it worked two weeks ago. Don't know much about javascript/jquery yet, but i'm slowly learning.

$(document).ready(function()
{
// Provide access to data outside of the getJSON call
var m_oJsonCollectie = null;
// Get the data
$.getJSON( "js/collectie.json", function(data)
{
// Set the data
m_oJsonCollectie = data;
// Apply the click handler
$( "#collectie li" ).click(function()
{
var thumb_id = $(this).data("id");
for(var i = 0; i < m_oJsonCollectie.stoelen.length; i += 1)
{
if(m_oJsonCollectie.stoelen[i].ref == thumb_id)
{
$("#detailimage") .attr('src', m_oJsonCollectie.stoelen[i].image);
$("#detailimage") .attr('title', m_oJsonCollectie.stoelen[i].title);
$("#title") .html('<h4> '+ m_oJsonCollectie.stoelen[i].naam+' </h4>');
$("#secondaryimage").attr('src', m_oJsonCollectie.stoelen[i].secondaryimage);
$("#secondaryimage").attr('title', m_oJsonCollectie.stoelen[i].secondarytitle);
$("#description") .html('<p> '+ m_oJsonCollectie.stoelen[i].description+' </p>');
}
}
});
});
});
JS have block level scope, so you wont get the values outside of the function unless you provide access to them or they are declared in global scope (which is considered bad practice).
This pattern should help you keep your data accessible, and only applies the click handler if the getJSON call is successful.

Check that your getJSON request is being received and returned by using deferred methods
// Syntax that will shed light to your issue :
$.getJSON
(
"js/collectie.json",
function (oJSON) { /*success*/ }
)
.done(function() { /* succeeded */ })
.fail(function() { /* failed */ })
.always(function() { /* ended */ });
I came to this conclusion due to comments and the fact that a variable only declared in the success handler for getJSON was undefined. Since the JSON containing variable was undefined, the success handler must never have been called. Chances are that the path to the JSON you are trying to get is incorrect.
Documentation for the methods to accomplish :
getJSON
done
fail
always
UPDATE
Knowing that the response is 304, and the results are undefined are the important details here. This issue has been addressed by jQuery already here
This is actually correct, given the ifModified header has not been set to false.
To fix this issue, use ajaxSetup() to modify the header.
NOTE : the use of this method is not recommended by jQuery, but in this case it works.
// place this is document ready handler before making any calls.
$.ajaxSetup({ ifModified : false });

Related

URL check with JS

I have two scripts, first of them clicks on the button and after that browser opens a new window, where i should click on the other button by the second script, is it possible to run them both at the same time, I mean like unite those scripts together?
function run() {
var confirmBtn = document.querySelector(".selector,anotherSelector ");
}
after this new window appears and here`s the second part of my script
var rooms = document.querySelectorAll(" .btn-a-offers");
console.log(rooms);
for (var room = 0; room < rooms.length; room++) {
rooms[room].click();
}
var prices = document.querySelectorAll(" .li-right-side>strong");
console.log(prices);
for (var price = 0; price < price.length; price++) {
}
var prices = [];
document.querySelectorAll(".new-pa-hotelsoffers .li-right-side > strong").forEach(function(price) {
prices.push(parseFloat(price.innerHTML.replace(/[^0-9.]/g, "")))
})
console.log(
Math.min(...prices).toFixed(2)
)
My English is not that good so I want to be sure that I explained everything right, second script must be executed in the new window, that opens after first script
Depending on the logical dependancy of your application and the use of the functions, you could execute the second function in a document.ready function on the second page.
Example:
<script>
//jQuery
$( document ).ready(function() {
secondFunction();
});
//Pure JS
function r(f){/in/.test(document.readyState)?setTimeout('r('+f+')',9):f()}
r(function() {
secondFunction();
});
</script>
However, if the page is to act independantly, and the second function is only to respond upon the execution of the first function, then that solution would not be the one you are looking for.
In the case where the function has to act entirely dependant on the use of the first function you could parse a value in the URL (better known as a GET variable) and check if that value is set.
Example:
<script>
functionOne() {
window.location.href = '/your_page.php?click=1';
}
</script>
Then on your second page you need to retrieve the GET variable.
<?php
$clicked = $_GET['click'];
?>
You can then perform a check to see if the variable has been set and fire your function upon that logic.
<?php
if($clicked != "") {
echo '
<script>
functionTwo();
</script>';
}
?>
Another way of doing it could be by the use of AJAX and have the other function execute in the AJAX' success function. That way you can eliminate the use of the GET variable, which is visible in the URL.
Example:
<script>
functionOne() {
$.ajax({
type : "POST", //or GET
url : "/your_page.php",
data : {
//parse your POST variable data if any
// variable : value,
// anotherVairable : anotherValue
// [....]
},
success: function (html) {
//Success handling
secondFunction();
}
})
}
</script>
Note that the AJAX used in the example is jQuery AJAX, so if you want to use some AJAX logic involving this structure, you'll need to include a jQuery library.
You should pass some parameter in the URL query like this:
// first-script.js
openNewWindow('http://example.com?run-second-script=1') // openNewWindow is fake function, just for demo
// second-script.js
if (window.location.search.includes('run-second-script=1')) { ... your code here ...}

Conditional addClass not working for each elements with same class

Les say I have some buttons with same class. On page load I am checking some value using ajax for each button. Depending on returned value of ajax request I want to add some class to the buttons, but it is not working,
$(document).ready(function(){
$('.add-remove-permissoion').each(function(){
var child = $(this).val();
var parent = $('#parent-name').text();
$.get('my-url', function(data){
if(data == 1){
$(this).addClass('glyphicon glyphicon-ok');
}else{
$(this).addClass('emptybox-blank');
}
});
});
});
I have checked that my ajax request is returning correct data. What is that I am doing wrong here?
The problem is the this reference inside the ajax callback, in the success callback this refers to the jqXHR object not the dom element reference that is why it is not working.
You can use a closure variable as given below to fix the problem
$(document).ready(function () {
$('.add-remove-permissoion').each(function () {
var $this = $(this),
child = $this.val();
var parent = $('#parent-name').text();
$.get('my-url', {}, function (data) {
if (data == 1) {
$this.addClass('glyphicon glyphicon-ok');
} else {
$this.addClass('emptybox-blank');
}
});
});
});
this in the context of the $.get handler doesn't refer to the element of the current iteration. Each function has it's own this value. You have several options.
Use the second parameter of the each callback.
$('.add-remove-permissoion').each(function(index, element) {
Use $.proxy or Function.prototype.bind method for setting the this value of the handler.
$.get('my-url', function(data) {
// ...
}.bind(this));
Cache the this value of the each handler and use it in your $.get handler.
var elem = this;
$.get('my-url', function(data) {
// ...
$(elem)...
});
Also note that there is a syntax error in your code:
$.get('my-url'}, function(data){
// -----------^
Problem is $(this) within ajax call does not refer to the button clicked.
Replace $(this).addClass with myElement.addClass. Create myElement within click event just before the ajax call: var myElement = $(this).

jQuery $.get returns white error page when handling errors

The following code gives me an error like this when I request a page and it comes back 404. Instead it should bring up an alert. What is strange is it only does this on links that have been ajaxed in, on links that don't update/change it works fine.
('.page-wrap').append('<img src="img/graphics/ajax-loader.gif" class="ajax-loader" />');
var target = $('section.content'),
siteURL = 'http://' + top.location.host.toString(),
internalLinks = $("a[href^='"+siteURL+"'], a[href^='/'], a[href^='./'], a[href^='../'], a[href^='#']"),
links = $('a'),
URL,
el,
mainContent,
headContent,
headClasses,
pageName,
ajaxSpinner = $('.ajax-loader');
internalLinks.click(function(e) {
el = $(this);
URL = el.attr('href');
$('.current_page_item').removeClass('current_page_item');
el.addClass("current_link").parent().addClass("current_page_item");
ajaxLoader(URL, false);
e.preventDefault();
});
function ajaxLoader(location, isHistory) {
$("html, body").animate({ scrollTop: "0px" });
ajaxSpinner.show();
$('.page-wrap').css('opacity', '0.5}');
// Load New Page
$.get(location, function(data) {
mainContent = $('section.content', data).html();
headContent = $('.feature-content', data).html();
pageName = $('.page-name', data).html();
headClasses = $('header', data).attr('class');
$('section.content').html(mainContent);
$('.page-name').html(pageName);
$('.feature-content').html(headContent);
if (headClasses) {
$('header').attr('class', headClasses);
} else {
$('header').removeClass();
}
if (!isHistory) {
history.pushState(location, '', location);
}
$(resizeHeader);
ajaxSpinner.fadeOut();
}).error(function() {
alert('woops'); // or whatever
});
}
w.bind('popstate', function(event) {
if (event.originalEvent.state !== null ) {
ajaxLoader(event.originalEvent.state, true);
}
});
First thoughts
Is it perhaps the case that something in your success handler code is causing an error of some kind? Like maybe the injection of whatever html that comes back the first successful time is causing the script to fail a second time?
What do you see playing out in your your Fiddler/Firebug/F12 developer tool of choice - you are using one of these, right? :) Keep an eye on any console errors...
Second thought
What jQuery version are you using?
I have tested this with jq 1.8.2 and the error handler works just fine for me, but if this is a JSONP request it won't trigger the error() function. I took the gist of your code:
$.get(
"404MeBaby.html", function (data) {
$(".result").html(data);
console.log(data);
}
).error(
function (x) {
console.log("well that didn't go so well...");
});
From the API:
As of jQuery 1.5, the success callback function is also passed a
"jqXHR" object (in jQuery 1.4, it was passed the XMLHttpRequest
object). However, since JSONP and cross-domain GET requests do not use
XHR, in those cases the jqXHR and textStatus parameters passed to the
success callback are undefined.
You could try using $.ajax instead as it gives a lot more control. Or, you can set the jQuery global ajax options as shown here that will affect all $.get calls, but remember the curse of JSONP, if relevant!

Basic Javascript Global Scope Issue

I'm having issues with scope in Javascript. Take a look at this code, for example:
$(function() {
var items = "GLOBAL";
$('.add').click(function() {
$.post("main/get", { 'get' : 'all' },
function(data){
items = String(data.result);
items = items.split(' *** ');
alert(items);
}, "json");
alert(items);
return false;
});
$(".add").autocomplete({
source: items
});
});
I'm trying to get autocomplete working, and it almost is. The only problem is that I can't seem to change items outside of the inner-most function. The first alert gives me what I'm looking for, but the second just gives me "GLOBAL." The bottom autocomplete part has to be able to access it.
Any help is appreciated!
Thanks!
It is not just a scope issue. Since your request is very likely to happen asynchronously (unless configured otherwise) it won't work that way anyway. You have to initialize the autocomplete in the callback function which gets called once your AJAX request is complete:
$(function() {
$('.add').click(function() {
$.post("main/get", { 'get' : 'all' },
function(data){
var items = String(data.result);
items = items.split(' *** ');
$(".add").autocomplete({
source: items
});
}, "json");
});
});

How can I determine/use $(this) in js callback script

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.

Categories

Resources