I have an application in which I am making multiple API calls and caching that data for later. Then someone else in the app, I want to retrieve that data and list it in a drop down using ng-option.
To get the cached data for each call, I am doing
var httpCache = $cacheFactory.get('$http');
var cachedImpactedEntities = httpCache.get('my api url');
This returns an object of an array in an array like so:
[200,"[ {
"entity_id": 1,"entity_desc": "test1" },
{"entity_id": 2,"entity_desc": "test2"}]",
{"content-type":"application/json;
charset=utf-8"},"OK"]
What would be a good way to extract just the inside array in quotes and output each "entity_desc" to the drop down using ng-option like:
test1
test2
...
The way the cached information comes back is confusing me.
Thanks.
If I understand you correctly the following shall be sufficient:
$scope.cachedEntities = eval(cachedImpactedEntities[1]);
<select ng-options="item as item.entity_desc for item in cachedEntities track by item.entity_id" ng-model="selected"></select>
But that means you will need to update "manually" the cachedEntities each time you get the data back from api call.
Consider of using promise construct:
$http.get("url+parameters").then(function(data) { $scope.cachedEntities = data}, function(){ // do something on error });
Related
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.
I have seen multipath update example. But before updating any data i have to push it at first place for which i was wondering if there is something called as multipath push?
I want to simultaneously push data under different set of nodes.
eg: Firebase scheme
-Examinations
- pushIdLk12203425
- pushIdML0124245
-RightChoices
- pushIdLk12203425
- pushIdML0124245
-Questions
- pushIdLk12203425
- pushIdML0124245
When i push value under examination node, same values or different values as per my backend architecture have to be pushed under RightChoices and Questions Node. Right now i am doing this using .then callback approach.
I push data under Examinations and then in its .then callback i push in RightChoice and Questions node.
But my concern is what if user closes the app and data just reaches Examinations node and never reaches RightChoices and Questions Node.
I am trying to figure out a better way of having data consistency.
Thanks.
Note: RightChoices and Questions are kept under different nodes for having a better security architecture and i cannot change the schema.
Would be grateful if somebody can help me out. Thanks.
I think you are looking for .update()
Have a look here: https://firebase.google.com/docs/database/web/read-and-write#update_specific_fields:
function writeMultipath(pushID1, pushID2) {
var data = {
id1: pushID1,
id2: pushID2
};
// Write the new data simultaneously to your DB-locations
var updates = {};
updates['/Examinations/'] = data;
updates['/RightChoices/'] = data;
updates['/Questions/'] = data;
return firebase.database().ref().update(updates);
}
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);
}
I feel like I must be missing something very basic. Here is a portion of my service:
angular.module('fire')
.constant('FIREBASE_URI', 'https://___.firebaseio.com/')
.factory('syncArraySvc', function(FIREBASE_URI, $firebaseArray) {
var buildingsUri = FIREBASE_URI + "buildings";
var buildings = $firebaseArray(new Firebase(buildingsUri));
console.log(buildings);
var getBuildings = function() {
return buildings;
};
var addBuilding = function(item) {
buildings.$add(item);
};
return {
getBuildings: getBuildings,
addBuilding: addBuilding
};
});
The console.log in the middle of that just returns an empty array. If I try to call the syncArraySvc.getBuildings() function from another controller, I also get an empty array. Somehow, $add(item) works, as does syncArraySvc.addBuilding(item). What am I missing?
If you look at $add $firebaseArray, It does create new item & add it into to $firebaseArray as like we have buildings. But as soon as you add item to ``$firebaseArray` it doesn't get added instantly. It get added when the $add promise get resolved.
I think you are doing correct thing, only you need call syncArraySvc.addBuilding(item) method on success of $add promise.
To make this approach you need to return a promise from the service method like
var addBuilding = function(item) {
return buildings.$add(item);
};
And then the caller function will take that promise and on resolve of it, he will call syncArraySvc.addBuilding(item) method that have assurity that items has added in buildings array.
syncArraySvc.addBuilding({foo: "bar"}).then(function(addedItem){
console.log(addedItem);
console.log(syncArraySvc.addBuilding(item)); //this will show you updated list
})
The other answers helped get me pointed in the right direction.
The API documentation has a code sample that doesn't seem to need the data to be wrapped in a promise:
var list = $firebaseArray(new Firebase(URL));
$scope.list = list;
However, it does point out that you can use the $loaded promise to be notified when the data is loaded. This is how I got it to work in my project:
syncArraySvc.getBuildings().$loaded(function(data) {
$scope.buildings = data;
});
I tried replicating this in a fresh project, and it consistently worked without the $loaded wrapper, like they show in the first example. It makes sense to me that the $loaded wrapper would be required. I don't understand how it could be working in the first example without it.
Try using a $timeout service inside the getBuildings function or rather when you call it. It probably takes a little while before data is returned.
I'm get a json object from an Ajax request like this:
"items":[
{
"id":923,
"id_str":"608475747557236737",
"uid":407388514,
"date":"Wed Jun 10 03:28:17 +0000 2015",
"status":0,
},
{
"id":923,
"id_str":"608475747557236737",
"uid":407388514,
"date":"Wed Jun 10 03:28:17 +0000 2015",
"status":0,
}
]
I loop the json object and generate HTML elements.
My question is if Is best store the json information in each HTML element such us: data-prop1="", data-prop2="" etc, o i keep the data in a javascript var like array?
The information of the HTML element will be send via Ajax request to the server again, so i want to store and restore to send.
From a performance point of view it is far better to store it in a variable instead of directly on your HTML elements
DOM operations are expensive (selecting/accessing that HTML element
which holds the data).
It's also the most cross-browser compatible way
since data attributes only apply on HTML5 browsers
It also easier to console.log it, and inspect it in your Developer tools.
Personally, I use the data-* attributes only when little information (such as a couple of attributes) is needed to be stored for each element and that information would be send by a direct click/hover event on the element itself - Otherwise it doesn't make much sense to me to store it within the DOM.
None is stopping you from saving whole JSON's on the DOM, if you find it easier - However if you keep on doing it you will end up with a very convoluted markup and a pattern that just looks terrible
I am working with a similar scenario currently and I've chosen to implement a model on the client's side which holds the information, because storing everything in the DOM could be harmful to the overall performance.
In other words I have some HTML code, for example
<div id='element-1' class='element'>foo</div>
<div id='element-2' class='element'>bar</div>
<div id='element-3' class='element'>baz</div>
which corresponds to the recieved data
[{id:1, text:'foo'}, {id:2, text:'bar'}, {id:3, text:'baz'}]
and instead of using DOM I have a model object which holds the data, is accessible from everywhere and has methods to search in the data, render it and so on.
A very simplified example of such object could look like this:
function Model() {
this.data = []; //after recieving the data via Ajax it is stored here
this.find = find;
function find(id) {
//cycle through data and return the correct record
}
this.render = render;
function render(id) {
var obj = find(id);
// find the element with $('#element-'+id) and update it's text
}
this.update = update;
function update(id, text) {
var obj = find(id);
obj.text = text;
}
}
The advantage is that you don't make the DOM heavy and you keep your data in a clean and organized way and the downfall is that you have to keep your displayed data and model data in sync.
I would recommend not to store anywhere in html, as you going to pass elements to another ajax request. So just create variable in javascript and store it temporary.