Array doesn't get filled correctly - javascript

I have these JavaScript entities: Item and Items.
var exports = {};
exports.Item = function(item) {
if (item) {
for (var attr in this.attributes) {
var value = item[attr];
if (value !== undefined) {
this.attributes[attr] = value;
}
}
}
return this;
};
exports.Item.prototype.attributes = {
_id: "",
title: ""
};
exports.Items = function(items) {
if (items && items.length > 0) {
for (var i = 0; i < items.length; i++) {
this.add(items[i]);
}
}
};
exports.Items.prototype.arr = [];
exports.Items.prototype.add = function(item) {
if (item) {
item = new exports.Item(item);
this.arr.push(item.attributes);
}
};
exports.Items.prototype.toJSON = function() {
var json = [];
for (var i = 0; i < this.arr.length; i++) {
json.push(this.arr[i]);
}
return json;
};
var i1 = new exports.Item({
_id: "1",
title: "1"
});
var i2 = new exports.Item({
_id: "2",
title: "2"
});
var i3 = new exports.Item({
_id: "3",
title: "3"
});
var items = new exports.Items([i1,i2,i3]);
console.log(items.toJSON());
There is a problem which I cannot find. When I execute the following code I get the last item 3 times instead of all the items.
I am sure the mistake is something small I cannot see. Maybe you can help me?

Member variables shouldn't be initialized in the prototype. Prototype variables will be shared across all instances. Instead, define the members in the constructor. So, instead of this:
exports.Items.prototype.arr = [];
Do this:
exports.Items = function(items) {
    this.arr = []; // instance variable
if (items && items.length > 0) {
for (var i = 0; i < items.length; i++) {
this.add(items[i]);
}
}
};

Related

upgrading into Components

I have just started learning to develop an angularJS app,with my final objective being updating the angular version. As an initial step I wanted to remove $scope and refactor the following code into components. I have tried replacing $scope with 'this' but it somehow seems to break the code. Can anyone show me how to go about this?
Tool.showTool({ catalogId: catalogId, data: 'showTool' },
function (data) {
$scope.catalog = data;
$scope.tools = data.tools;
$scope.tools.filters = [];
$scope.tools.applicableFlagValues = [];
for (var index = 0; index < data.tools.length; index++) {
data.tools[index].category = angular.copy(data.tools[index].subCategory.tsCategory.category);
data.tools[index] = $scope.initItem($scope, data.tools[index], catalogId);
}
angular.forEach($scope.tools, function (detailedTool) {
GenericFilterService.addFilterItemsAsProperty(detailedTool, $scope.tools.filters);
ApplicableFlagService.addFlagValuesAsProperty(detailedTool, $scope.tools.applicableFlagValues);
});
if (nfrId !== undefined && nfrId !== '') {
Tool.calculateToolsProgressScoring({ tools: $scope.tools, nfrId: nfrId }, function (data, headers) {
var toolProgressList = data.result;
for (var index = 0; index < $scope.tools.length; index++) {
$scope.tools[index].progressCode = toolProgressList[index].progress;
$scope.tools[index].scoringVal = toolProgressList[index].scoring;
$scope.tools[index].criticalityAns = toolProgressList[index].criticality;
$scope.tools[index].compliancyAns = toolProgressList[index].compliancy;
$scope.tools[index].compliantAnsCount = toolProgressList[index].compliantAnsCount;
$scope.tools[index].totalAnsCount = toolProgressList[index].totalAnsCount;
}
});
}
if (tsId !== undefined && tsId !== '') {
Tool.calculateToolsProgressPerTs({ tools: $scope.tools, tsId: tsId }, function (data, headers) {
var toolProgressList = data.result;
for (var index = 0; index < $scope.tools.length; index++) {
$scope.tools[index].tsProgressCode = toolProgressList[index].progress;
$scope.tools[index].tsUsageAns = toolProgressList[index].usage;
$scope.tools[index].tsVersAns = toolProgressList[index].version;
$scope.tools[index].tsOtherVersAns = toolProgressList[index].otherversion;
$scope.tools[index].compliancyAns = toolProgressList[index].compliancy;
}
});
}
});

Push to an array in a nested loop is repeating the last value

I am trying to push elements to an array in a nested loop, but only the last item is getting repeated in the final array, where am I going wrong, very new to javascript asynchronous concept.Below is the function in which I push the items to an array.
$scope.showBeList = function(feed) {
if (feed[srcServ.KEY_CONTENT_TEXT]) {
var content = JSON.parse(feed[srcServ.KEY_CONTENT_TEXT])
if (content) {
$scope.beList = {};
for (var key in content) {
var decorationVal;
//reading value from a lokijs collection
var decoration = dataServ[srcServ.CONST_COLLECTION_DECORATION].find({
'name': key
});
if (decoration && decoration.length) {
decorationVal = decoration[0];
if (decorationVal != null) {
var tempObj = JSON.parse(decorationVal.value);
if (tempObj) {
var header = tempObj[key][key + '_HEADER'];
if (header) {
var counter = content[key].length;
var tempItems = [];
for (var j = 0; j < content[key].length; j++) {
(function(j) {
var obj = {};
obj[srcServ.KEY_MAIN_HEADER] = tempObj[key][srcServ.KEY_DESC];
obj[srcServ.KEY_SUB_HEADER] = header[srcServ.KEY_DESC];
obj.id = j;
var itemVal = content[key][j][key + '_HEADER'];
var details = [];
var notes = [];
for (var item in itemVal) {
var val = null;
var found = false;
for (var i = 0; i < header.field.length; i++) {
if (header.field[i].name == item) {
val = header.field[i];
found = true;
break;
}
}
if (found && val != null) {
val[srcServ.KEY_DESC_VALUE] = itemVal[item];
details.push(val);
}
}
obj.details = details;
counter--;
if (counter == 0) {
$scope.showMoreDetails = true;
$scope.beList.beItems = tempItems;
console.log(JSON.stringify($scope.beList));
}
tempItems.push(obj)
})(j);
// $scope.beList.beItems.push(obj);
}
}
}
}
}
}
}
}
}

JSOM dynamicly get two announcements from all lists in all webs

Need help with the chaining. The functions work. But async calls make it hard for me to get everything. Help me think right!
My thought:
Get All Webs recursively (function works)
Get all lists from webs and iff announcementlist add to array and pass along
Get two items from all announcmentlists and sort by created.
Add ALL announcement items into one large array (to be able to sort array later.
Heres the code,
function getAllWebs(success, error) {
var ctx = SP.ClientContext.get_current();
var web = ctx.get_site().get_rootWeb();
var result = [];
var level = 0;
result.push(web);
var getAllWebsInner = function (web, result, success, error) {
level++;
var ctx = web.get_context();
var webs = web.get_webs();
ctx.load(webs, 'Include(Title,Webs,ServerRelativeUrl)');
ctx.executeQueryAsync(
function () {
for (var i = 0; i < webs.get_count() ; i++) {
var web = webs.getItemAtIndex(i);
result.push(web);
if (web.get_webs().get_count() > 0) {
getAllWebsInner(web, result, success, error);
}
}
level--;
if (level == 0 && success)
success(result);
},
error);
};
getAllWebsInner(web, result, success, error);
}
function error(sender, args) {
console.log(args.get_message());
};
function getAnnouncementLists(web, success, error) {
var dfd = $.Deferred();
var ctx = web.get_context();
var collList = web.get_lists();
var result = []
ctx.load(collList, 'Include(Title, Id, BaseTemplate)');
ctx.executeQueryAsync(function () {
for (var i = 0; i < collList.get_count() ; i++) {
var list = collList.getItemAtIndex(i);
var bTemp = list.get_baseTemplate();
if (bTemp == 104) {
result.push(list);
}
}
//success(result);
dfd.resolve(result);
}, error);
return dfd.promise();
}
function getListItems(list, success, error) {
var dfd = $.Deferred();
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query><OrderBy><FieldRef Name="Created" Ascending="False"></FieldRef>'
+ '</OrderBy></Query><ViewFields><FieldRef Name="Title"/><FieldRef Name="Body"/>' +
'<FieldRef Name="Created"/></ViewFields><RowLimit>2</RowLimit></View>');
var listItems = list.getItems(camlQuery);
var result = []
var ctx = list.get_parentWeb().get_context();
ctx.load(listItems);
ctx.executeQueryAsync(function () {
for (var i = 0; i < listItems.get_count() ; i++) {
var item = listItems.getItemAtIndex(i);
result.push(item);
}
dfd.resolve(result);
//success(result);
}, error);
return dfd.promise();
}
function printResults(items) {
var sortedItems = items.sort(dynamicSort("get_created()"));
alert(sortedItems);
}
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
$(document).ready(function () {
var items = getAllWebs(
function (allwebs) {
var array = [];
for (var i = 0; i < allwebs.length; i++) {
getAnnouncementLists(allwebs[i]).then(function (announceLists) {
for (var i = 0; i < announceLists.length; i++) {
getListItems(announceLists[i]).then(function (items) {
array.push(items);
});
}
});
}
return array;
}
);
//getAllWebs(
// function (allwebs) {
// for (var i = 0; i < allwebs.length; i++) {
// getAnnouncementLists(allwebs[i],
// function (announceLists) {
// for (var i = 0; i < announceLists.length; i++) {
// getListItems(announceLists[i],
// function (items) {
// printResults(items);
// }, error);
// }
// }, error);
// }
// }, error);
});
Given the requirements to retrieve list items from Announcements lists located across site collection, below is demonstrated the modified example that contains some improvements such as:
the number of requests to the server is reduced
fixed the issue in getAllWebs function that prevents to return any results if site contains only a root web
Example
function getAllWebs(propertiesToRetrieve,success, error) {
var ctx = SP.ClientContext.get_current();
var web = ctx.get_site().get_rootWeb();
var result = [];
var level = 0;
ctx.load(web, propertiesToRetrieve);
result.push(web);
var getAllWebsInner = function (web, result, success, error) {
level++;
var ctx = web.get_context();
var webs = web.get_webs();
var includeExpr = 'Include(Webs,' + propertiesToRetrieve.join(',') + ')';
ctx.load(webs, includeExpr);
ctx.executeQueryAsync(
function () {
for (var i = 0; i < webs.get_count() ; i++) {
var web = webs.getItemAtIndex(i);
result.push(web);
if (web.get_webs().get_count() > 0) {
getAllWebsInner(web, result, success, error);
}
}
level--;
if (level == 0 && success)
success(result);
},
error);
};
getAllWebsInner(web, result, success, error);
}
function loadListItems(lists,query,success,error,results){
var results = results || [];
var curList = lists[0];
var ctx = curList.get_context();
var listItems = curList.getItems(query);
ctx.load(listItems);
ctx.executeQueryAsync(function () {
results.push.apply(results, listItems.get_data());
lists.shift();
if(lists.length > 0) {
loadListItems(lists,query,success,error,results);
}
if(lists.length == 0)
success(results);
}, error);
}
function dynamicSort(property) {
var sortOrder = 1;
if (property[0] === "-") {
sortOrder = -1;
property = property.substr(1);
}
return function (a, b) {
var result = (a[property] < b[property]) ? -1 : (a[property] > b[property]) ? 1 : 0;
return result * sortOrder;
}
}
var propertiesToRetrieve = ['Lists.Include(BaseTemplate)','ServerRelativeUrl'];
getAllWebs(propertiesToRetrieve,
function(allwebs){
//1. get filtered lists
var allAnnouncementLists = [];
allwebs.forEach(function(w){
var announcementLists = w.get_lists().get_data().filter(function(l){
if(l.get_baseTemplate() == SP.ListTemplateType.announcements)
return l;
});
allAnnouncementLists.push.apply(allAnnouncementLists, announcementLists);
});
//2.Load list items from lists
var query = new SP.CamlQuery(); //<-set your custom query here
loadListItems(allAnnouncementLists,query,
function(allListItems){
//3.Sort and print results
var sortedItems = allListItems.sort(dynamicSort("get_created()"));
sortedItems.forEach(function(item){
console.log(item.get_item('Title'));
});
},logError);
},
logError);
function logError(sender,args){
console.log(args.get_message());
}

Grouping objects of array for knockout binding

I have an objects array that has 27 length:
[object(array)]
....
....
Each item in this array is empty or consists of an objects of array which has properties as shown below. This could have several loops so it will have many objects.
function MainTests(testName, section, totalExpected, totalPasssed, totalDuration, loopExpected, loopPassed, loopDuration) {
var self = this;
self.sectionName = section;
self.testName = testName;
self.totalPassExpect = totalExpected;
self.totalPassRate = totalPasssed;
self.totalDuration = totalDuration;
self.loopPassExpected = loopExpected;
self.loopPassRate = loopPassed;
self.loopDuration = loopDuration;
}
I want to group by sectionName and testName like this:
{
section: sectionName,
tests: [testName:testName, totalPassExpect: totalExpected........loopDuration:loopDuration..]
}
I tried this but it only groups it by sectionName:
self.GroupMainTest = ko.computed(function () {
var mainTestArray = [];
for (var i = 0; i < allMainTests.length ; i++) {
var group = {};
var result = allMainTests[i];
if (result.length != 0) {
for (var j = 0; j < result.length; j++) {
if (group[result[j].sectionName] == undefined) {
group[result[j].sectionName] = [group[result[j].sectionName]];
}
group[result[j].sectionName].push(result[j].sectionName)
group[result[j].sectionName].push(result[j].totalPassExpect)
group[result[j].sectionName].push(result[j].totalPassRate)
group[result[j].sectionName].push(result[j].totalDuration)
group[result[j].sectionName].push(result[j].loopPassExpected)
group[result[j].sectionName].push(result[j].loopPassRate)
group[result[j].sectionName].push(result[j].loopDuration)
group[result[j].sectionName].push(result[j].testName)
}
mainTestArray.push(group);
}
else {
mainTestArray.push(result);
}
}
return mainTestArray;
});
My goal is to achieve similar to this plnkr.
Can you help?

Find an element in an array recursively

I have an array of objects. Every object in the array has an id and an item property that is an array containing other object. I need to be able to find an element in an array by id. Here is a sample of what I have done so far, but the recursive function is always returning undefined.
How can I quit the function and return the item when I have called the function recursively several times?
$(function () {
var treeDataSource = [{
id: 1,
Name: "Test1",
items: [{
id: 2,
Name: "Test2",
items: [{
id: 3,
Name: "Test3"
}]
}]
}];
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems && subMenuItems.length > 0) {
for (var i = 0; i < subMenuItems.length; i++) {
var item;
if (subMenuItems[i].Id == id) {
item = subMenuItems[i];
return item;
};
getSubMenuItem(subMenuItems[i].items, id);
};
};
};
var searchedItem = getSubMenuItem(treeDataSource, 3);
alert(searchedItem.id);
});
jsFiddle
You should replace
getSubMenuItem(subMenuItems[i].items, id);
with
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
in order to return the element when it is found.
And be careful with the name of the properties, javascript is case sensitive, so you must also replace
if (subMenuItems[i].Id == id) {
with
if (subMenuItems[i].id == id) {
Demonstration
Final (cleaned) code :
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].id == id) {
return subMenuItems[i];
}
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
}
}
};
I know its late but here is a more generic approach
Array.prototype.findRecursive = function(predicate, childrenPropertyName){
if(!childrenPropertyName){
throw "findRecursive requires parameter `childrenPropertyName`";
}
let array = [];
array = this;
let initialFind = array.find(predicate);
let elementsWithChildren = array.filter(x=>x[childrenPropertyName]);
if(initialFind){
return initialFind;
}else if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childrenPropertyName]);
});
return childElements.findRecursive(predicate, childrenPropertyName);
}else{
return undefined;
}
}
to use it:
var array = [<lets say an array of students who has their own students>];
var joe = array.findRecursive(x=>x.Name=="Joe", "students");
and if you want filter instead of find
Array.prototype.filterRecursive = function(predicate, childProperty){
let filterResults = [];
let filterAndPushResults = (arrayToFilter)=>{
let elementsWithChildren = arrayToFilter.filter(x=>x[childProperty]);
let filtered = arrayToFilter.filter(predicate);
filterResults.push(...filtered);
if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childProperty]);
});
filterAndPushResults(childElements);
}
};
filterAndPushResults(this);
return filterResults;
}

Categories