I have an object (array type) ,its console representation looks like following image . please see the image
This array is created by restangulr using following code ,
restangularProvider.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
if (operation == "getList") {
var extractedData;
extractedData = data.result;
extractedData.paginginfo = data.paginginfo;
return extractedData;
}
if (operation != "get") {
var item = { status: response.status };
feedBackFactory.showFeedBack(item);
}
return response.data;
});
How can I read the elements from this array, I want to extract properties like paginginfo ,also object collection
// The EDIT :1 js libraries I used here angularjsu 1.3.4, and restangular 1.4
My app.js : here I configured rest angular provider
restangularProvider.addResponseInterceptor(function(data, operation, what, url, response, deferred) {
if (operation == "getList") {
var extractedData;
extractedData = data.result;
extractedData.paginginfo = data.paginginfo;
return extractedData;
}
if (operation != "get") {
var item = {
status: response.status
};
feedBackFactory.showFeedBack(item);
}
return response.data;
});
// according to my knowledge this function will intercept every ajax call (api calls) and modify the response , unfortunately I need to apply custom modification because the getlist method must return collection but my api returning object, so according to restangular ,the above code is the possible solution, and here its fine its fetching the data.
userservice.js : this is angular service which using restangular
function(restangular) {
var resourceBase = restangular.all("account");
this.getUsers = function(pagenumber, recordsize) {
var resultArray = resourceBase.getList({
page: pagenumber,
size: recordsize
}).$object;
};
};
according to my knowledge .$object in restangulr resolve the promise and bring back the data, also I am getting the resultArray its looks like in the image in the console, here I can log this array so I think I got all the data from server and filled in this object. I applied some array accessing techniques available jquery and JavaScript like index base accessing , associate accessing but I am getting undefined ie.
resultArray[1] //undifiend;
In angular you can use angular.forEach(items, function(item){ //your code here});
Where items is the array you want to traverse.
If you want to access to one specific position use [], for example var item= items[5].
Then you can do item.property.
UPDATE
Your problem is that you are setting properties in an Array JS Object:
extractedData.paginginfo = data.paginginfo;
You should return the object data like it is and in your controller do something like:
var results= data.result;
var pagInfo= data.paginationInfo;
angular.forEach(results,function(result){});
It looks like the array is numerically indexed (0..1..5); you should be able to simply iterate through it using ForEach (in Angular) or .each (in Jquery).
Something like (JQuery):
$.each(array, function(key, value)
{
// key would be the numerical index; value is the key:value pair of the array index's element.
console.log(value.firstname); // should print the firstname of the first element.
});
First of all, as I said in the comments, you shouldn't be attaching named properties to arrays. Return an object thact contains what you need:
if (operation == "getList") {
return { values: data.result, paging: data.pagingInfo };
}
The getList() method returns a promise, so you need to use that:
this.getUsers = function(pagenumber, recordsize) {
resourceBase.getList({
page: pagenumber,
size: recordsize
}).then(function (data) {
console.log(data.values[0]);
console.log(data.paging.totalRecords);
});
};
Related
I am storing an array of Javascript objects in Parse under the name 'AcceptedInvitees'. The objects each have two values; an example entry is:
[{"id":"QpAETvSYaB","type":"Requested"},{"id":"Ojjp3TdmTM","type":"unknown"},{"id":"STAUUgVxJp","type":"unknown"},{"id":"AXBC5iZvKQ","type":"unknown"},{"id":"YixKjqrjTM","type":"unknown"},{"id":"b2YwmMcO6n","type":"unknown"},{"id":"DjZePR0Wif","type":"unknown"},{"id":"94Harl1hxm","type":"unknown"},{"id":"1bOE07B0C8","type":"unknown"}]
I am trying to retrieve this value using .get("AcceptedInvitees"), but I am being returned an array of empty objects. For example, retrieving the above entry gives me
[{},{},{},{},{},{},{},{},{}]
This is the specific code I am using to query the data. All the other fields are being retrieved without a problem, but printing node.children gives me the above.
var query = new Parse.Query("UserInvite");
query.include("AcceptedInvitees");
query.get(id, {
success: function (user) {
node.name = user.get("name");
node.TotalInvitees = user.get("TotalInvitees");
node.type = type;
node.children = user.get("AcceptedInvitees");
}
Any help with this would be greatly appreciated!
Parse.Query expects Parse.Object. Therefore, do as following:
var UserInvite = Parse.Object.extend("UserInvite");
var id = 'someUserInviteId';
var query = new Parse.Query(UserInvite);
query.include("AcceptedInvitees");
query.get(id, {
success: function(obj) {
console.log(obj.toJSON());
},
error: function(err) {
console.log(err);
}
});
I have application on AngularJs.
I have variable in scope, which is initialized with data from API. $scope.receivedRequests = CurrentUserData.incomeRequests();
Cause request to API takes some time, $scope.receivedRequests is empty at start.
$scope.receivedRequests I've used with ng-repeat
<div class="full-row" ng-repeat="row in receivedRequests | filterByStatus:[State.PENDING] | partition:3 track by $index">
This data is also filtered.
But when I tried to replace this filtering into controller, like
$scope.filterByStatus = function (statuses) {
return $filter('filterByStatus')($scope.receivedRequests, statuses);
};
$scope.pendingRequests = $scope.filterByStatus([State.PENDING]);
$scope.pendingRequests were always empty.
How can I filter data in the controller?
.filter('filterByStatus', function () {
return function(arr, statuses) {
if (!arr) { return; }
return arr.filter(function(value) {
return statuses.some(function(val) {
return value.status == val;
});
});
};
});
$scope.receivedRequests is just array of elements, that have string property status (alos id, date etc.) as example : status : "Pending"
In that case I would use promises and split the code like this.
Factory service
app.factory('myService', function($http){
return {
getRequests: function(){
return $http.get('http://someurl');
}
}
})
Controller
app.controller('myController', function(myService){
$scope.filteredArray = [];
myService.getRequests()
.then( function(data){
$scope.filteredArray = $scope.filterFunction(data);
})
$scope.filterFunction = function(array){
//function logic
//...
}
})
Notes:
The trick here is done by calling the filtering function inside the then() function. This way you are sure the data from the API is been already fetched and after that you can filter it.
I am not sure how your $scope.recievedRequests object look, can you try the below... why don't you send the State.pending value with an associated key for your array.
$scope.filterByStatus = function (statuses) {
return $filter('filterByStatus')($scope.receivedRequests, statuses);
};
$scope.pendingRequests = $scope.filterByStatus({key: State.PENDING})[0];
I'm having a json object I get from a get request in an angular application. It gives me two main attributes data and included. The included object is somehow a relationship with the data object. For example data shows messages and included the senders of those messages. I managed to associate every message with the sender by checking if an attribute from the data object is the same with another attribute in the included object. here is my code
$http.get('data.json').then(
function(jsonAPI) {
console.log(jsonAPI);
var dataObj = {};
var messages = [];
$.each(jsonAPI.data.data, function(x, data) {
dataObj[x] = data;
$.each(jsonAPI.data.included, function(y, included) {
if (data.relationships.sender.data.id == included.id) {
dataObj[x].sender = included;
}
});
messages.push(dataObj[x]);
});
$scope.newMessages = messages;
},
function(errorResponse) {
// todo handle error.
}
);
I create a new array that contains all the data object and also sender's information under the sender attribute. The problem is that a new relationship is added called user_data_template. I want with a similar way to be able to pass to the messages array the corresponding user_data_template data. How can I change the above nested $each function to achieve that?
Here is a working plunker
I managed to find the solution. I had to change the code to the following:
$.each(jsonAPI.data.data, function(x, data) {
dataObj[x] = data;
$.each(jsonAPI.data.included, function(y, included) {
if(data.relationships.sender.data.id == included.id && included.type == "user") {
dataObj[x].sender = included;
}
if(data.relationships.user_data_template.data !== undefined) {
if(data.relationships.user_data_template.data.id == included.id && included.type == "user_data_template") {
dataObj[x].question = included;
}
}
});
messages.push(dataObj[x]);
});
And the new plunker
Please help me prepend items when they are pushed over Firebase RESTful service, new item should be on top order when the are displayed in DOM with ng-repeat.
//post.js service
var ref = new Firebase(FIREBASE_URL + 'posts');//creates posts object on root of url
var posts = $firebase(ref);//we get posts Object from firebase
....
var Post = {
create: function(post){
return posts.$add(post);
}
.....
//posts.js controller
$scope.submitPost = function(){
Post.create($scope.post).then(function(){
console.log('success! post submitted');
});
}
HTML:
<div class="col-xs-12" ng-repeat="(postId, post) in posts">
{{post.title}}
{{post.url}}
</div>
But in DOM the newest item goes at the bottom, where as I need the new item should be on the top.
Is there any unshift method in AngularFire ($firebase) ?
If you don't want to get into setting priorities, a simple solution is to let Firebase order your list naturally and reverse it on the client side using a filter such as:
angular.module("ReverseFilter",[])
.filter('reverse', function() {
function toArray(list) {
var k, out = [];
if( list ) {
if( angular.isArray(list) ) {
out = list;
}
else if( typeof(list) === 'object' ) {
for (k in list) {
if (angular.isObject(list[k])) { out.push(list[k]); }
}
}
}
return out;
}
return function(items) {
return toArray(items).slice().reverse();
};
});
Add this module dependency to your app and you'll have a filter that you can use in the ng-repeat attribute like this:
(ng-repeat="(idx, entry) in journal.months[0] | reverse")
Keeping in mind that Firebase stores JSON objects, never arrays, it should make sense that it's not possible to perform an unshift operation against a list. (What would that mean to an object whose keys are sorted lexicographically?) You'll need to utilize priorities and ordered data if you want your item to appear first. Or, if the list is terse, just sort client side.
Here's a quick and dirty way to implement unshift, although this will almost always be inferior to utilizing proper data ordering or simply using endAt():
app.factory('OrderedList', function($FirebaseArray, $firebase, $firebaseUtils) {
var OrderedList = $FirebaseArray.$extendFactory({
unshift: function(data) {
var self = this, list = this.$list;
self.$add(data).then(function(ref) {
var newId = ref.name();
var pos = self.$indexFor(newId);
if( pos > 0 ) {
// place the item first in the list
list.splice(0, 0, list.splice(pos, 1)[0]);
// set list priorities to match
self.reorder();
}
});
},
// order items by their current index in the list
reorder: function() {
var list = this.$list;
angular.forEach(list, function(rec, i) {
rec.$priority = i;
list.$save(rec);
});
}
});
return function(ref) {
return $firebase(ref, {arrayFactory: OrderedList}).$asArray();
}
});
Keep in mind that this particular example is not concurrency safe (if multiple users are modifying the same list at the same time, it's going to have some unpredictable results). Implementing a concurrency-safe solution is similar, but use-case specific (the method for generating the priorities will depend on the use case).
I have a JavaScript object that I am stringifying with JSON.stringify that returns a JSON string with parent and children data.
When I try to parse this string back to an object, the children objects are now null.
function cacheForm(agency) {
var agency = ko.toJS(this); //easy way to get a clean copy
delete agency.contacts; //remove an extra property
for (i in agency.offices) {
for (val in agency.offices[i]) {
//delete agency.offices[i].agency;
//delete agency.offices[i].agencyID;
}
}
for (i in agency.offices) {
for (ii in agency.offices[i].contacts) {
for (val in agency.offices[i].contacts[ii]) {
//delete agency.offices[i].contacts[ii].office;
//delete agency.offices[i].contacts[ii].agencyID;
//delete agency.offices[i].contacts[ii].officeID;
}
}
}
var value = agency;
var cache = [];
parsed = JSON.stringify(value, function (key, value) {
if (typeof value === 'object' && value !== null) {
if (cache.indexOf(value) !== -1) {
// Circular reference found, discard key
return;
}
// Store value in our collection
cache.push(value);
}
return value;
});
var data = JSON.parse(parsed);
}
Edit
Agency part of my view model that I am passing into my cacheForm function and I am using
var agency = ko.toJS(this);
to have my data available in an object which can be parsed to JSON string. I may of deleted this code in my post because my original code had many annotations.
Your question initially showed a screen shot where data.offices = [null] was highlighted.
It's not a parsing error, but an error in stringify. Your paste already has data.offices = [null].
MDN states regarding replacer:
Note: You cannot use the replacer function to remove values from an array. If you return undefined or a function then null is used instead.
And furthermore regarding stringify:
If undefined, a function, or an XML value is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array).
I don't have access to your original object, and hence cannot tell which of the two you are hitting...
Implementing toJSON (or just explicitly constructing another object from the source object) instead of a replacer to filter arrays would be the way to go, if the problem is within your current replacer implementation.
there are various js libraries predefined for parsing json and to get children values . What i usually do to parse json is use http://developer.yahoo.com/yui/json/ YUI library.
So I eventually solved my problem and this is how I did it.
function cacheForm(agency) {
// GET my object from agency vm
var agency = ko.toJS(agency);
var s = YUI().use("json-stringify", function (Y) {
var jsonStrAgency = Y.JSON.stringify(agency, ["activities", "agencyName", "agencyID", "campaignBillings", "category", "declaredBillings", "immediateParent", "numberOfEmployees", "ultimateParent", "uRL"]); // Use an array of acceptable object key names as a whitelist.
var jsonStrOffices, jsonStrContacts;
for (i in agency.offices) {
jsonStrOffices = Y.JSON.stringify(agency.offices, ["address1", "address2", "address3", "address4", "address5", "agencyID", "faxNumber", "officeID", "postCode", "telephoneNumber"]);
for (ii in agency.offices[i].contacts) {
jsonStrContacts = Y.JSON.stringify(agency.offices[i].contacts, ["agencyID", "emailAddress", "firstName", "jobName", "officeID", "personID", "surName", "title"]);
}
}
localStorage.setItem('Agency', jsonStrAgency);
localStorage.setItem('Offices', jsonStrOffices);
localStorage.setItem('Contacts', jsonStrContacts);
});
}
Firstly I am passing in my ko.observableArray to the function cacheForm. This parameter is called agency and it is part of my viewmodel.
I want to parse my observableArray and convert it into a standard javascript object. By using ko.toJS I can do this. There will be no ko constructors after using toJS.
Then I have to get my JSON strings. Since my object has children and grandchildren I have to parse these parts separately. Stringify doesn't like arrays within an object, they will be changed to null and your children data will be lost.
Because of circular recursion, I have to use this:
var s = YUI().use("json-stringify", function (Y) {
This is part of the Yahoo API. This is the script reference:
<script src="http://yui.yahooapis.com/3.11.0/build/yui/yui-min.js"></script>
Y.JSON.stringify takes an object as one parameter and an option paremter which is an array. The purpose of this array is to contain the property names of the object you want to stringify. From other forums I found out this is known as whitelisting.
With all my JSON strings I can store them in HTML5 local storage.
When the page loads I then check to see if my local storage contains data. If true I retrieve my data and serialize from JSON string to a javascript object.
define(['services/datacontext'], function (dataContext) {
var initialized = false;
var agency;
if (localStorage.Agency && localStorage.Offices && localStorage.Contacts) {
var objAgency = new Object(ko.mapping.fromJSON(localStorage.getItem('Agency')));
var objOffices = new Object(ko.mapping.fromJSON(localStorage.getItem('Offices')));
var objContacts = new Object(ko.mapping.fromJSON(localStorage.getItem('Contacts')));
objAgency.offices = objOffices;
objAgency.offices._latestValue[0].contacts = objContacts;
agency = ko.observableArray([ko.mapping.fromJS(objAgency)]);
ko.applyBindings(agency);
initialized = true;
}
else {
agency = ko.observableArray([]);
}
Finally I reconstruct my object to how it was before stringify and map it back to an observableArray and finally bind it.
Hopefully this helps other people using a combination of knockoutJS and complicated objects.
See below for my full code:
define(['services/datacontext'], function (dataContext) {
var initialized = false;
var agency;
if (localStorage.Agency && localStorage.Offices && localStorage.Contacts) {
var objAgency = new Object(ko.mapping.fromJSON(localStorage.getItem('Agency')));
var objOffices = new Object(ko.mapping.fromJSON(localStorage.getItem('Offices')));
var objContacts = new Object(ko.mapping.fromJSON(localStorage.getItem('Contacts')));
objAgency.offices = objOffices;
objAgency.offices._latestValue[0].contacts = objContacts;
agency = ko.observableArray([ko.mapping.fromJS(objAgency)]);
ko.applyBindings(agency);
initialized = true;
}
else {
agency = ko.observableArray([]);
}
var save = function (agency, myStoredValue) {
// Clear Cache because user submitted the form. We don't have to hold onto data anymore.
//amplify.store("Agency", null);
return dataContext.saveChanges(agency);
};
var vm = { // This is my view model, my functions are bound to it.
//These are wired up to my agency view
activate: activate,
agency: agency,
title: 'agency',
refresh: refresh, // call refresh function which calls get Agencies
save: save,
cacheForm: cacheForm
};
return vm;
function activate() {
vm.agency;
if (initialized) {
return;
}
initialized = false;
return refresh();
}
function refresh() {
return dataContext.getAgency(agency);
}
function cacheForm(agency) {
// GET my object from agency vm
var agency = ko.toJS(agency);
var s = YUI().use("json-stringify", function (Y) {
var jsonStrAgency = Y.JSON.stringify(agency, ["activities", "agencyName", "agencyID", "campaignBillings", "category", "declaredBillings", "immediateParent", "numberOfEmployees", "ultimateParent", "uRL"]); // Use an array of acceptable object key names as a whitelist.
var jsonStrOffices, jsonStrContacts;
for (i in agency.offices) {
jsonStrOffices = Y.JSON.stringify(agency.offices, ["address1", "address2", "address3", "address4", "address5", "agencyID", "faxNumber", "officeID", "postCode", "telephoneNumber"]);
for (ii in agency.offices[i].contacts) {
jsonStrContacts = Y.JSON.stringify(agency.offices[i].contacts, ["agencyID", "emailAddress", "firstName", "jobName", "officeID", "personID", "surName", "title"]);
}
}
localStorage.setItem('Agency', jsonStrAgency);
localStorage.setItem('Offices', jsonStrOffices);
localStorage.setItem('Contacts', jsonStrContacts);
});
}
});