Parse JSON data, and then pass all its values to another function - javascript

I'm building this website: http://collections.design
The way it works is by reading all tools data from a JSON, using jQuery (I don't know much javascript). Then, you can click on an item and a side panels opens with further information. But there's a lot of repeated code, so I'm trying to optimise it a bit.
First I parse the JSON:
// The data source
var data_source = "../data/tools/tools.json";
// Parsing the JSON
$.getJSON(data_source, function(data) {
$.each(data, function(key,val) {
// And I'm storing all of its values in variables, to make them easier to read:
var name = val.availability.name;
var linux = val.os.linux;
// Then I'm using all that to render each item on screen
…
});
});
Each of the items has a button that calls another function to create and open the side panel. The side panel reuses that item's data from the JSON. This function to create the side panel is using the name variable as parameter, but then inside is parsing the JSON again to get the rest of the values it needs.
My question is:
How can I "encapsulate" all variables when I do the JSON parsing, then pass it as a parameter to the other function; and finally, individually read each of those values in the other function?
I tried working with arrays. But didn't manage it to work, also keeping in mind that I'm trying to simplify things, not repeat myself, and keep short names…
Maybe I'm asking too much, but any pointers or links to doc will be appreciated.

I see two ways of doing this.
1) Save the JSON data outside the scope so you can reuse it and pass the index of the data you want.
Something like this
// The data source
var data_source = "../data/tools/tools.json";
var all_data;
// Parsing the JSON
$.getJSON(data_source, function(data) {
all_data = data;
$.each(data, function(key,val) {
$('.button').on('click', function() { callToOtherFunction(key) })
});
});
function callToOtherFunction(key) {
console.log(all_data[key]);
}
2) As Sam Axe said, pass the data directly to the function
// The data source
var data_source = "../data/tools/tools.json";
// Parsing the JSON
$.getJSON(data_source, function(data) {
$.each(data, function(key,val) {
$('.button').on('click', function() { callToOtherFunction(key) })
});
});
function callToOtherFunction(val) {
console.log(val);
}
Here's a working fiddle.

The data is already "encapsulated" in the data object. Pass that object to the function that you want to use the data in.
You could always construct a new object - but what's the point - it's already in the data object.

Related

How to access and use multiple data from json object? Do I need to make an array?

I am a beginner and using $.get to retrieve data from a rest API such as:
[{"id":"1","url":"http:\/\/123.456.78.910\/workforce\/images\/item1.jpg","price":"99","description":"Mobile Phone"},
{"id":"2","url":"http:\/\/123.456.78.910\/workforce\/images\/item2.jpg","price":"98","description":"Laptop"}
{"id":"3","url":"http:\/\/123.456.78.910\/workforce\/images\/item3.jpg","price":"92","description":"Console"}] }
$.get('http://xxxxxxxxxxx,
function (data) {
var obj = $.parseJSON(data);
So from what I understand I have retrieved the data from the REST API and parsed it so it is stored in a variable called obj.
My question is, how do I access and use each unique record in the obj variable?
Each record has it's own picture (item1.jpg, item2.jpg etc).
Whem my app loads I want it to show the item1.jpg image, and I want to be able to navigate to the other item pictures using buttons (previous / next).
I also want the description and price to be displayed underneath in some text input fields.
What I have figured so far is that I should:
Iterate through the obj variable, and store each record into an array.
Upon app initialisation I can set the default value for the image placeholder to array[index0].url, and set the description and price fields.
I can then set the previous and next buttons to array[currentIndex-1] or array[currentIndex+1].
Would this be the best way to do it?
Or can I just do this without using an array and manipulate the obj.data directly?
Thanks!!!
I may not be understanding what exactly what you want to do but I think I have the gist. If you just want to show the picture then the array of just images probably wouldn't be a bad idea. However, it looks like the Jason you're getting is already in an array. You can just use array index notation to get to what you want.
ie)
var arr = //your json response ;
var current = 0; //sets currently displayed object to the first in the array
var setCurrent = function () {
var image = arr[current]["url"];
}
You can then modify current however you want (on click on arrow iterate up/down, etc) then call the setCurrent function to set your image the the one you want. Hope that helps!
You can use the response you have from $.get() directly.
It is an array of objects.
You can use it like this:
console.log(data[2].description);
// outputs: "Console"
I've made a CodePen demo where it has a 4th object with a real image url to show you how to use the url info...
EDIT
Just in case you wouldn't know this:
You can use the response inside the scope of the $.get() callback...
You can not use it straith after the $.get() outside the callback since $.get() is asynchronous.
You can use it in some other handler wich will happen after the response is received.
var getResponse;
$.get('http://xxxxxxxxxxx', function (data) {
getResponse = data;
console.log(data[2].description);
// outputs: "Console"
console.log(getResponse[2].description);
// outputs: "Console"
});
console.log(getResponse[2].description);
// outputs: "Undefined"
// But since this handler will be triggered long after the response is obtained:
$("#somebutton").click(function(){
console.log(getResponse[2].description);
// outputs: "console"
});
In order for your page javascript to be able to access the data retrieved from your ajax request, you'll need to assign it to some variable which exists outside the callback function.
You will need to wait until the ajax request has been processed before you can read the array. So you might want to set the actual default image to be something that doesn't rely on the ajax request (a local image).
Here's a simple approach
// fake testing ajax func
function fakeget (url, callback) {
setTimeout(callback(JSON.stringify([
{"id":"1","url":"http:\/\/123.456.78.910\/workforce\/images\/item1.jpg","price":"99","description":"Mobile Phone"}, {"id":"2","url":"http:\/\/123.456.78.910\/workforce\/images\/item2.jpg","price":"98","description":"Laptop"},
{"id":"3","url":"http:\/\/123.456.78.910\/workforce\/images\/item3.jpg","price":"92","description":"Console"}
])), 1000);
}
// real code starts here
// global variables for ajax callback and setImg func to update
var imageData, currentImg;
// change this back to $.get for real
fakeget('http://xxxxxxxxxxx',
function (data) {
imageData = $.parseJSON(data);
setImg(0);
}
);
function setImg(index) {
// turns negative indices into expected "wraparound" index
currentImg = (index % imageData.length + imageData.length) % imageData.length;
var r = imageData[currentImg];
$("#theImg").attr('src', r.url);
$('#theDescription').text(r.price + " " + r.description);
}
$("#prev").click(function () {
setImg(currentImg - 1);
});
$("#next").click(function () {
setImg(currentImg + 1);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<img id='theImg' src='somedefault.jpg'>
<div id='theDescription'></div>
</div>
<button id='prev'>Prev</button>
<button id='next'>Next</button>
Few observations :
Your JSON Object is not a valid JSON.
No need to parse it again your data is already a JSON Object.
Working fiddle
var data = [{"id":"1","url":"http:\/\/123.456.78.910\/workforce\/images\/item1.jpg","price":"99","description":"Mobile Phone"},{"id":"2","url":"http:\/\/123.456.78.910\/workforce\/images\/item2.jpg","price":"98","description":"Laptop"}, {"id":"3","url":"http:\/\/123.456.78.910\/workforce\/images\/item3.jpg","price":"92","description":"Console"}];
for (var i in data) {
var imgUrl = data[i].url;
console.log(imgUrl);
}

Appending new results to an open jQuery autocomplete menu

I have an app in which I have multiple search sources. Previously, the users had to choose in what source to search in before searching. If they did not choose, the app would default to one of the options.
However, now they want to search in all the sources at the same time. This is fine enough, but the problem is that when one of the searches returns, it overwrites the previous search result. Pretty much expected behavior. What I basically want is to append the new results to the already open autocomplete menu, instead of overwriting the old results. Naturally, the autocomplete menu would have to empty when it closes.
I guess that this is possible to do, but what approach is the best? I could just have an array I guess, which I append results to and then overwrite _renderMenu to use this array instead of the items one that is passed to the function. Then empty said array at the close event.
Is this the best way to go though? Or is there a more elegant solution?
Some code:
Ok, so searchAction is called by jquery autocomplete eventually. In collection.search I do the ajax call, here the URL is created based in the this parameter, then respondWhithData is called and maps the search result to a proper format (ie value and label for the autocomplete menu). After reponse is called from respondWithData, jquery automagically renders the resultsmenu. Thus, I probably have to overwrite the reponse event function as well as the _renderMenu and possibly _renderItem, yes?
searchAction: function(searchTerm, collection, response){
var self = this;
$.when(collection.search(searchTerm, this)).then(function(data) {
self.respondWithData(data, response);
});
},
respondWithData : function(data, response) {
if (data.length > 0) {
var responseVal = _.map(data, this.mapData);
this.checkResponseCount(responseVal);
response(responseVal);
}
else {
response(this.emptyResult());
}
},
To be clear, the problem is not the multiple search itself, but rendering the asynchronos results. I want to render the first results that come back, and then appends the rest as soon as they are returned from the server.
Edit 2:
Just tried to edit ui.content in the autocompleteresponse event, but any edit does not take once it renders for some reason...
Edit 3: Ah, ui.content can only be modified directly, not changed. If I push every single change instead of concating two arrays ui.content shows what I want.
It works I guess, but its not perfect.
I can figure how looks your scenario but I'm guessing:
You should have like:
function search1() {
$.ajax({ ...
success: function(data) {
$('#myResultsDiv").html(data)
}
});
}
etc
Instead of overwritting the #myResultsDiv you need to Append the results like:
function search1() {
$.ajax({ ...
success: function(data) {
$('#myResultsDiv").append(data)
}
});
}
Edit: You can also do something like this:
var resultsArray = [];
var searchDone = 0;
var totalSearchs = 5; //assuming 5 searches
function search1() {
function search1() {
$.ajax({ ...
success: function(data) {
//APPEND data to resultsArray
searchDone++;
if(searchDone==totalSearch) //syncronize the 5 searchs before render
renderSearchs(resultsArray);
}
});
}

jQuery autocomplete + data attributes returned uiAutocomplete in the result

I am trying to use the autocomplete from jQueryUI. I need to do a data call to the backend, but other than the value from request.term there are other parameters i need to pass as well, so instead of using some other means if passing the additional data, i thought of using the data- attributes to do it.
var input = $(document.createElement("input"));
mydata.each(function() {
input.attr('data-'+this.nodeName, this.innerHTML);
});
So when i build my <input> i also put a brunch of data- attributes in there, the idea is that when i need to do the autocomplete call, i should be able to just do input.data() and grab everything i need.
However, i am getting some weird behavior from jQuery's .data() call.
input.autocomplete({
source: function(req, resp) {
$.ajax({
url: $(this.element).attr('action'),
dataType : 'json',
data: $(this.element).data(),
cache : false
}).done(function(resp) {
console.log(resp);
}).fail(function() {
alert("failed");
});
},
...
In the above code, when i do $(this.element).data(), it does indeed returned my all the attributes that i defined, but it also included something else, such as the uiAutocomplete object...
I thought the .data call is supposed to return only the items with prefix data-? What is the best way to grab the data- attributes?
This is because jQuery uses data attribute to store plugins namespace data in it, the more plugin used in it, the more data namespaces you will get. This is not weird, this is how jQuery works. As it is said here -
Calling jQuery.data( element ) retrieves all of the element's
associated values as a JavaScript object. Note that jQuery itself uses
this method to store data for internal use, such as event handlers, so
do not assume that it contains only data that your own code has
stored.
Reference:
https://api.jquery.com/jQuery.data/
As far as your solution, you should namespace your data if you wish to retrieve it later. Something like -
input.data('mydata', {name:'test'});
and then get it by -
var data = input.data('mydata');
In my observation the data method were returning the values set as below
1)setting the values
$(".autoCompleteInput").data("attribute1", "value1");
$(".autoCompleteInput").data("attribute2", "value2");
$(".autoCompleteInput").data("attribute3", 4);
$(".autoCompleteInput").data("attribute4", 5);
2) Getting the values
var datas = $(".autoCompleteInput").data();
3)assigning the values to other control
var stringData = JSON.stringify(datas);
$(".DataDisplay").val(stringData );
http://api.jquery.com/data/
Creating an Autocomplete sample
1)Created another page that returns a string of values used for autocomplete.
2)Made a Ajax request and retrieved the values into a local Array.
3)used the Array of values to Populating the AutoComplete.
4)incase of some widgets Make sure you are including the necessary jquery library and some related css into your page.
$(document).ready(function () {
$.ajax({
url: "AutoCompleteDataProvider.cshtml",
success: function (data) {
var autoCompleteValue = data.split(',');
$(".autoCompleteInput").autocomplete({
source: autoCompleteValue
});
},
error: function (textStatus) {
alert(textStatus);
}
});
});

Sorting Dynamic Data with Isotope

I am trying to use Isotope.js to sort data by type. There seem to be a few ways to do this however they all require that you know the sort variables before hand.
One of the best examples of what I'm talking about is found in this question.
In the example they are trying to sort by class for example group all elements with class .milk like so:
milk: function( $elem ) {
var isMilk = $elem.hasClass('milk');
return (!isMilk?' ':'');
},
A jsfiddle is provided here: http://jsfiddle.net/Yvk9q/9/
My problem:
I am pulling the categories (classes or data-type) from a user generated database. For this reason I cannot simply add all the sorting variables to the code before hand.
I played with the fiddle and got a semi working sort here: http://jsfiddle.net/BandonRandon/erfXH/1/ by using data-category instead of class. However,this just sorts all data alphabetically not by actual category.
Some possible solutions:
Use JSON to return an array of all categories and then use this to loop through classes
Use inline javascript and run a PHP loop inside a <script> tag
Write an external PHP file with a javascript header
What I'm looking for
The simplest best approach here, being if it's one of the solutions above or something different. This doesn't seem like it should need to be this complicated. So I may be over complicating this.
EDIT:
I now have a json array of my data but I can't figure out how to pass the data into the isotope settings when i try something like this
var $container = $('.sort-container');
var opts = {
itemSelector: '.member-item',
layoutMode: 'straightDown',
getSortData : {
$.getJSON( 'member-cat-json.php', function(data) {
$.each(data, function(i, item) {
var slug = data[i].slug;
slug : function( $elem ) {
var is+slug = $elem.hasClass(slug);
return (!is+slug?' ':'');
}
}
});
});
}
}
var $container = $('.sort-container');
$container.isotope(opts);
It fails because I can't use a loop inside of the plugin settings. Not sure what can be done about this though.
EDIT 2:
I found this question which seems about what I'm trying to do but unfortunately the most recent jsfiddle fails with isotope
Here is a sample of my JSON output:
{term_id:9, name:Milk, slug:milk, term_group:0, term_taxonomy_id:17...}
{term_id:9, name:Eggs, slug:eggs, term_group:0, term_taxonomy_id:17...}
I am using the slug as the class name and in my loop.
I'm not sure I entirely understand your question, but I'll state my assumptions and work from there:
You have data in a format as described above:
{term_id:9, name:Milk, slug:milk, term_group:0, term_taxonomy_id:17...}
You want to sort on the slug names, even though we do not know what the slugs will be named ahead of time.
Assuming these two things, the fiddle you've linked to is close, but has a problem due to closures which I have fixed.
As expected, your situation is similar to the one listed, except that you need to obtain the JSON data first, as you have.
var $container = $('.sort-container'),
createSortFunction = function(slug) {
return function($elem) {
return $elem.hasClass(slug) ? ' ' : '';
};
},
getSortData = function(data) {
var sortMethods = {};
for (var index in data) {
var slug = data[index].slug;
// immediately create the function to avoid
// closure problems
sortMethods[slug] = createSortFunction(slug);
}
return sortMethods;
}
$.getJSON('member-cat-json.php', function (data) {
// I'm wrapping the isotop creation inside the `getJSON`
// call, just to ensure that we have `data`
$container.isotope({
itemSelector: '.member-item',
layoutMode: 'straightDown',
getSortData: getSortData(data);
});
});

how to serialize a form without jQuery? [duplicate]

This question already has answers here:
form serialize javascript (no framework)
(25 answers)
Closed 8 years ago.
For a lot of reasons (first of all: learning javascript), I need to serialize a form without jQuery, and send the resulting serialized data-structure to a php page with ajax.
The serialized data must be in JSON format.
How can I do that?
--EDIT--
this is how my form looks like: http://jsfiddle.net/XGD4X/
I am working on a similar problem, and I agree that it is worthwhile to learn how to program first without using a framework. I am using a data object (BP.reading) to hold the information, in my case a blood pressure reading. Then the JSON.stringify(dataObj) dose the work for you.
Here is the handler for the 'save' button click, which is a method on the dataObj. Note I am using a form instead of a table to input data, but the same idea should apply.
update: function () {
var arr = document.getElementById("BP_input_form").firstChild.elements,
request = JDK.makeAjaxPost(); // simple cross-browser httpxmlrequest with post headings preset
// gather the data and store in this data obj
this.name = arr[0].value.trim();
...
this.systolic = arr[3].value;
this.diastolic = arr[4].value;
// still testing so just put server message on page
request.callback = function (text) {
msgDiv.innerHTML += 'server said ' + text;
};
//
request.call("BP_update_server.php", JSON.stringify(this));
}
I hope this is helpful
* edit to show generic version *
In my program, I am using objects to send, receive, display, and input the same kind of data, so I already have objects ready. For a quicker solution you can just use a empty object and add the data to it. If the data is a set of the same type of data then just use an array. However, with a object you have useful names on the server side. Here is a more generic version untested, but passed jslint.
function postUsingJSON() {
// collect elements that hold data on the page, here I have an array
var elms = document.getElementById('parent_id').elements,
// create a post request object
// JDK is a namespace I use for helper function I intend to use in other
// programs or that i use over and over
// makeAjaxPost returns a request object with post header prefilled
req = JDK.makeAjaxPost(),
// create object to hold the data, or use one you have already
dataObj = {}, // empty object or use array dataArray = []
n = elms.length - 1; // last field in form
// next add the data to the object, trim whitespace
// use meaningful names here to make it easy on the server side
dataObj.dataFromField0 = elms[0].value.trim(); // dataArray[0] =
// ....
dataObj.dataFromFieldn = elms[n].value;
// define a callback method on post to use the server response
req.callback = function (text) {
// ...
};
// JDK.makeAjaxPost.call(ULR, data)
req.call('handle_post_on_server.php', JSON.stringify(dataObj));
}
Good Luck.
CoffeeScript implementation returning a GET query string:
serialize = (form) ->
enabled = [].filter.call form.elements, (node) -> not node.disabled
pairs = [].map.call enabled, (node) ->
encoded = [node.name, node.value].map(encodeURIComponent)
encoded.join '='
pairs.join '&'
Or if you rather prefer a key-value map:
serialize = (form) ->
data = {}
for node in form.elements when not node.disabled and node.name
data[node.name] = node.value
data
I haven't looked at jQuery's implementation, so no 100% compatibility guaranteed.

Categories