Anyway to `angular.copy(..., ...)` without replacing data? - javascript

I have an angular factory with a function that loads a range of items from a list via an API. So if I wanted to load the first 10 I would say something like getRange(0, 10). Once the JSON returns from the API, I copy the items over to a local model using angular.copy... But how do I load the next 10 and copy the list items over, without deleting the old ones. Apparently, I can't continue to use angular.copy because it deletes the old items and then copies over the new items.
Any guidance?

You can think something like this:
var app = angular.module('plunker', []);
app.controller('demoController', function($scope) {
$scope.arr = []; // data from factory.
for (var i = 0; i < 100; i++) { // for demo filling it up
$scope.arr.push({ item: i }); // just like this
}
$scope.newArr = []; // the new item array;
$scope.len = $scope.newArr.length || 10;
$scope.getItems = getItems;
function getItems() {
for (var i = $scope.len - 10; i < $scope.len; i++) {
$scope.newArr.push(angular.copy($scope.arr[i]))
}
$scope.len += 10;
}
});
Take a look at the plnkr here.

Related

How to reuse controller without adding a similar one? Angular1.5

I've done 2 tables(customers , items ) CRUD pages in my web app.
CRUD customer table(customer.html)
CRUD Item table(item.html)
I'm trying to make a new page , which is similar to CRUD customer.html page but can CRUD one specific customer id's items.
the way i'm going to make it is copying two similar pages I've done.
customer.html -> crudOneCustomersItems.html
item.html -> item2.html
Then I created another 1 controller:itemCtrl2 in app.js , copy similar code but changed data source(items belong to one customer's id).
crudOneCustomersItems.html
item2.html
But I think maybe I can reuse same controllers , how can I make it in Angular1.5??
my demo plunker: https://plnkr.co/edit/4hfNde9tLIIDzZRJAlhe
app.controller('CustomerCtrl', function($scope) {
// making data start
$scope.customer = {
id:1,
name:'jason',
email:'pp#pp.cc'
};
$scope.customers = [];
for(var i = 1 ; i < 20 ; i++){
var temp = angular.copy($scope.customer);
temp.id = i;
temp.name = temp.name+i;
temp.email = temp.name+i;
$scope.customers.push(temp);
}
//making data end
});
app.controller('ItemCtrl', function($scope) {
// making data start
$scope.item = {
id:1,
customerId: 2,
name:'bomb',
description:'it can explode'
};
$scope.items = [];
for(var i = 1 ; i < 20 ; i++){
var temp = angular.copy($scope.item);
temp.id = i;
if(i<10){
temp.customerId =2;
}
else{
temp.customerId =3;
}
temp.name = temp.name+i;
temp.description = temp.name+i;
$scope.items.push(temp);
}
//making data end
});
app.controller('ItemCtrl2', function($scope) {
// getting selected data (customer id from querying parameter )
});
Thanks

AngularJS - Is controller code executed line by line?

I'm new to AngularJS, and is experimenting AngularJS with Twitch API.
I have a list of channels that I'm interested in, defined as var channels.
Then I use the $http.get function to loop through another array, twitchList.channels, which contains the API addresses that I'm supposed to call.
(function() {
var app = angular.module('twitchList', []);
app.controller('twitchController', ['$http', function($http){
var twitchList = this;
twitchList.channels = [];
var channels = ["freecodecamp", "storbeck", "terakilobyte", "habathcx","RobotCaleb","thomasballinger","noobs2ninjas","beohoff", "MedryBW"];
for (var i = 0; i < channels.length; i++ ) {
twitchList.channels.push({
name: channels[i],
api: 'https://api.twitch.tv/kraken/streams/' + channels[i],
})
}
var data_list = [];
for (var j = 0; j < twitchList.channels.length; j++) {
$http.get(twitchList.channels[j].api).success(function(data){
data_list.push(data);
})
}
// Issue arises here!
console.log(data_list);
console.log(data_list.length);
}]);
})();
The API calls seems to be working perfectly, however, I need to get the results of the API call into an array, called data_list. Now, when I print data_list, and data_list.length, what happens is that data_list.length always returns 0, and data_list is sometimes populated (meaning it's either 0 size array or 9 size array). Even though the property of the array has a length 9, but calling .length always gives 0.
This let me think that the controller code is not executed line by line? Or is there something wrong with my logic?
Can someone give me a pointer? Thanks
No, this line:
data_list.push(data);
will be executed when you receive a response on the http request sent a line above. Hence the following lines:
console.log(data_list);
console.log(data_list.length);
will output [] and 0
I've not used it before, but could you possibly use $q.all in order to resolve multiple promises? I've used the equivalent $.when function in jQuery to achieve this in the past.
var data_list = [];
var promise_array = [];
var request;
for (var j = 0; j < twitchList.channels.length; j++) {
request = $http.get(twitchList.channels[j].api);
request.success(function(data) {
data_list.push(data);
});
promise_array.push(request);
}
$q.all(promise_array).then( function() {
console.log(data_list);
console.log(data_list.length);
});

AngularJS - Collecting multiple get requests into json array and then passing to directive

I am new to angular and been struggling how to solve my problem.
I need to access API multiple times for users data, store everything as JSON array and when all the data is collected(all results as one array) it needs to be passed to directive which will use it to draw visualization(eg. d3.js-pie chart).
$scope.allData = [];
$http.get("****link here****/students")
.success(function (data) {
students = data;
for (i = 0; i < students.length; i = i + 1) {
$http.get("**** link here ****/quest/" + students[i].id)
.success(function (data) {
quest = data;
$scope.allData.push({
id: quest.id,
value: quest.length
});
}
}
and then pass it to directive as
<bar-chart data='allData'></bar-chart>
even if I set watch in directive and have scope as '=' the directive gets empty array.
In my other code when I just do one http get call for json array I can pass it to directive easily and it works fine.
EDIT1:
OK so I use premises now, but still allData array is 0.
Even with simple example like this:
$scope.allData = [];
var promieses = [];
for (i = 0; i < 10; i = i + 1) {
promieses.push($http.get("***link***/student/" + students[i].id));
}
$q.all(promieses).then(function (data) {
for (i = 0; i < data.length; i = i + 1) {
$scope.allData.push("test");
}
});
in html {{ allData ]] // 0
This is a great place to unleash the power of $q. You can wait for all the promises to resolve and then process them using $q.all method. It simply Combines multiple promises into a single promise that is resolved when all of the input promises are resolved.
See this example:
students = data;
var promises = [];
for (i = 0; i < students.length; i = i + 1) {
promises.push($http.get("**** link here ****/quest/" + students[i].id));
}
$q.all(promises).then(function(response) {
for (var i = 0; i < response.length; i++) {
$scope.allData.push({
id: response[i].data.id,
value: response[i].data.length
});
}
})
See it in action here: http://plnkr.co/edit/TF2pAnIkWquX1Y4aHExG?p=preview

Javascript: loop through array

This is driving me crazy. I'm just trying to print out an array and it's not working. What am I missing? The results variable is returning "undefined" which much mean my for loop isn't working correctly. Everything else works properly, the console.log I have correctly displays the fields are added to the array.
// The list of accounts array.
var accountsArray = [];
function addAccount() {
// Take fields and put user data into varables.
var accountName = document.getElementById('accountName').value;
var accountBalance = document.getElementById('accountBalance').value;
var accountType = document.getElementById("accountType");
var accountTypeSelected = accountType.options[accountType.selectedIndex].text;
var accountCurrency = document.getElementById("accountCurrency");
var accountCurrencySelected = accountCurrency.options[accountCurrency.selectedIndex].text;
// Put these variables into the array.
accountsArray.push(accountName);
accountsArray.push(accountBalance);
accountsArray.push(accountTypeSelected);
accountsArray.push(accountCurrencySelected);
// Items added to the array, logged.
console.log('user added: ' + accountsArray);
}
function accountsListHtml() {
var results;
// Loop through the array
for (var i = 0; i < accountsArray.length; i++) {
results = accountsArray[i];
}
document.getElementById('accountsList').innerHTML = results;
}
Here's a link to all the files. It's an iOS web app using Framework7. Balance Pro
You are calling accountsListHtml() in body.onload. At that point accountsArray is empty.
I can't find any other possibility to call accountsListHtml() on that page you linked to.
Add one line inside function addAccount() and it will work:
function addAccount() {
/* vour code */
console.log('user added: ' + accountsArray);
accountsListHtml(); // add this line
}
Try changing results = accountsArray[i]; to results += accountsArray[i];.
Update
And initialize results with an empty string, for example :)
for (var i = 0; i < accountsArray.length; i++) {
results = accountsArray[i];
}
The statement in the for loop i.e. results = accountsArray[i]; overwrites the variable results evry loop run. You could change the statement to :
results += accountsArray[i].toString();
and initialise results to an empty string.
The following works for me: http://jsfiddle.net/95ztrmk3/13/
HTML:
<div id="accountsList"></div>
JS:
// The list of accounts array.
var accountsArray = [];
addAccount();
accountsListHtml();
function addAccount() {
// Take fields and put user data into varables.
var accountName = "John Doe";
var accountBalance = "500.00";
var accountTypeSelected = "Checking"
var accountCurrencySelected = "USD";
// Put these variables into the array.
accountsArray.push(accountName);
accountsArray.push(accountBalance);
accountsArray.push(accountTypeSelected);
accountsArray.push(accountCurrencySelected);
// Items added to the array, logged.
console.log('user added: ' + accountsArray);
}
function accountsListHtml() {
var results = [];
// Loop through the array
for (var i = 0; i < accountsArray.length; i++) {
results += accountsArray[i] + " ";
}
document.getElementById('accountsList').innerHTML = results;
console.log(results);
}
Assuming the input isn't malformed or otherwise weird. I made sure Javascript recognizes results is an empty array and not a string or something: var results = []

return from JS function

basic JS question, please go easy on me I'm a newb :)
I pass 2 variables to the findRelatedRecords function which queries other related tables and assembles an Array of Objects, called data. Since findRelatedRecords has so many inner functions, I'm having a hard time getting the data Array out of the function.
As it currently is, I call showWin inside findRelatedRecords, but I'd like to change it so that I can get data Array directly out of findRelatedRecords, and not jump to showWin
function findRelatedRecords(features,evtObj){
//first relationship query to find related branches
var selFeat = features
var featObjId = selFeat[0].attributes.OBJECTID_1
var relatedBranch = new esri.tasks.RelationshipQuery();
relatedBranch.outFields = ["*"];
relatedBranch.relationshipId = 1; //fac -to- Branch
relatedBranch.objectIds = [featObjId];
facSel.queryRelatedFeatures(relatedBranch, function(relatedBranches) {
var branchFound = false;
if(relatedBranches.hasOwnProperty(featObjId) == true){
branchFound = true;
var branchSet = relatedBranches[featObjId]
var cmdBranch = dojo.map(branchSet.features, function(feature){
return feature.attributes;
})
}
//regardless of whether a branch is found or not, we have to run the cmdMain relationship query
//the parent is still fac, no advantage of the parent being branch since cmcMain query has to be run regardless
//fac - branch - cmdMain - cmdSub <--sometimes
//fac - cmdMain - cmdSub <-- sometimes
//second relationship query to find related cmdMains
var relatedQuery = new esri.tasks.RelationshipQuery();
relatedQuery.outFields = ["*"];
relatedQuery.relationshipId = 0; //fac -to- cmdMain
relatedQuery.objectIds = [featObjId];
//rather then listen for "OnSelectionComplete" we are using the queryRelatedFeatures callback function
facSel.queryRelatedFeatures(relatedQuery, function(relatedRecords) {
var data = []
//if any cmdMain records were found, relatedRecords object will have a property = to the OBJECTID of the clicked feature
//i.e. if cmdMain records are found, true will be returned; and continue with finding cmdSub records
if(relatedRecords.hasOwnProperty(featObjId) == true){
var fset = relatedRecords[featObjId]
var cmdMain = dojo.map(fset.features, function(feature) {
return feature.attributes;
})
//we need to fill an array with the objectids of the returned cmdMain records
//the length of this list == total number of mainCmd records returned for the clicked facility
objs = []
for (var k in cmdMain){
var o = cmdMain[k];
objs.push(o.OBJECTID)
}
//third relationship query to find records related to cmdMain (cmdSub)
var subQuery = new esri.tasks.RelationshipQuery();
subQuery.outFields = ["*"];
subQuery.relationshipId = 2;
subQuery.objectIds = [objs]
subTbl.queryRelatedFeatures(subQuery, function (subRecords){
//subRecords is an object where each property is the objectid of a cmdMain record
//if a cmdRecord objectid is present in subRecords property, cmdMain has sub records
//we no longer need these objectids, so we'll remove them and put the array into cmdsub
var cmdSub = []
for (id in subRecords){
dojo.forEach(subRecords[id].features, function(rec){
cmdSub.push(rec.attributes)
})
}
var j = cmdSub.length;
var p;
var sub_key;
var obj;
if (branchFound == true){
var p1 = "branch";
obj1 = {};
obj1[p1] = [cmdBranch[0].Branches]
data.push(obj1)
}
for (var i=0, iLen = cmdMain.length; i<iLen; i++) {
p = cmdMain[i].ASGMT_Name
obj = {};
obj[p] = [];
sub_key = cmdMain[i].sub_key;
for (var j=0, jLen=cmdSub.length; j<jLen; j++) {
if (cmdSub[j].sub_key == sub_key) {
obj[p].push(cmdSub[j].Long_Name);
}
}
data.push(obj);
}
showWin(data,evtObj) <---this would go away
})
}
//no returned cmdRecords; cmdData not available
else{
p = "No Data Available"
obj = {}
obj[p] = []
data.push(obj)
}
showWin(data,evtObj) <--this would go away
})
})
}
I'd like to have access to data array simply by calling
function findRelatedRecords(feature,evt){
//code pasted above
}
function newfunct(){
var newData = findRelatedRecords(feature,evt)
console.log(newData)
}
is this possible?
thanks!
Edit
Little more explanation.....
I'm connecting an Object event Listener to a Function like so:
function b (input){
dojo.connect(obj, "onQueryRelatedFeaturesComplete", getData);
obj.queryRelatedFeatures(input);
console.log(arr) //<----this doesn't work
}
function getData(relatedFeatData){
var arr = [];
//populate arr
return arr;
}
So when obj.QueryRelatedFeatures() is complete, getData fires; this part works fine, but how to I access arr from function b ?
Post Edit Update:
Due to the way that this event is being hooked up you can't simple return data from it. Returning will just let Dojo call to the next method that is hooked up to onSelectionComplete.
When init runs it is long before findRelatedRecords will ever be executed/fired by the onSelectionComplete event of the well, which is why you were seeing undefined/null values. The only way to work with this sort of system is to either 1) call off to a method like you're already doing or 2) fire off a custom event/message (technically it's still just calling off to a method).
If you want to make this method easier to work with you should refactor/extract snippets of it to make it a smaller function but contained in many functions. Also, changing it to have only one exit point at the end of the findRelatedRecords method will help. The function defined inside of subTbl.queryRelatedFeatures() would be a great place to start.
Sorry, you're kind of limited by what Dojo gives you in this case.
Pre Edit Answer:
Just return your data out of it. Everywhere where there is a showWin call just use this return.
return {
data: data,
evtObj: evtObj
}
Then your newfunct would look like this.
function newfunct(){
var newData = findRelatedRecords(feature,evt);
console.log(newData);
console.log(newData.data);
console.log(newData.evtObj);
}
If you only need that "data" object, then change your return to just return data;.
Also, start using semicolons to terminate statements.

Categories

Resources