Angularjs foreach only returns one object - javascript

This could be something simple and I'm overlooking it. But I'm building out a filter by categories and once a user clicks a category it updates a scope (my instance $scope.productStuff) and display the objects accordingly. My problem is when I click the category it gives me back the mulitple objects in my console. Then I look at the dom and it only shows one object (and it's the last object) instead all the objects that are in my console.
Here is my function:
$scope.update = function(val) {
angular.forEach($scope.productStuff, function(item){
if( item.s2 === val.toUpperCase()){
$scope.productStuff = [item];
}
});
}
Here is my factory that's getting the data on page load
dataFactory.getProducts().then(function(res){
$scope.productStuff = res.data;
$scope.loading = false;
});
So my question is why is it displaying one object in the dom and multiple objects in the console and how do I put the items on the $scope.productStuff?

$scope.update = function(val) {
// Create an empty array
var stuff = [];
angular.forEach($scope.productStuff, function(item){
if( item.s2 === val.toUpperCase() ){
// push to our array when condition is met (filter)
stuff.push(item);
}
});
// $scope.productStuff now contains all the filtered items
$scope.productStuff = stuff;
}

You are trying to modify iterate over and modifying $scope.productStuff too. As soon as you write:
$scope.productStuff = [item];
only one item remains in it. try creating a new array and once done assign it to $scope.productStuff
$scope.update = function(val) {
var tempArray = [];
angular.forEach($scope.productStuff, function(item){
if( item.s2 === val.toUpperCase()){
tempArray.push(item);
}
});
$scope.productStuff = tempArray;
}

Related

How to prevent object to add duplicate value and stop excuting function

Hey guys i am adding data to the array as object but i wanted to if there is any duplicate item code so its stop excuting the function and return and if the the condition is true so its take the constructor value and add itno the data structure
This what i try to prevent it from adding the value but its not work as i want
function getNo(b){
for (const [key, value] of Object.entries(data)) {
let val = value.itemCode;
if(b === val){
alert('Its equalt to item code');
break;}else{ return b;};
}}
----What i want is-----
1) Check if value is duplicate or not from the itemCode constructor
2)If its a duplicate value so its should show and alert and stop excuting the function
3)And add this function into the addItem function to check its duplicate or not
4)I store value in the data array
var item = function(name,itemCode,stock){
this.name = name;
this.itemCode = itemCode;
this.stock = stock;
}
var data = [];
function addItem(name,itemCode,stock){
var Newitem = new item(name,itemCode,stock);
data.push(Newitem);
}
addItem('BlueTee',100,50);
addItem('Yellow tee',101,100);
addItem('BrownTee',102,120);
There are multiple ways to handle this. Your choice should depend on other use cases.
The easiest way is to define data as a javascript object instead of an array. This would require keys for each object. This would look like this:
var data = {};
function addItem(name, itemCode, stock){
var newItem = new item(name, itemCode, stock);
if(data[itemCode] === undefined)
data[itemCode] = newItem;
}
If you are going to later access data as an array, then you can instead iterate over the array for each insertion. This would look like this:
function addItem(name, itemCode, stock){
var newItem = new item(name, itemCode, stock);
if(!data.some(function(x => x.itemCode === itemCode)){
data.push(newItem);
}
}
This would be slower than a normal insertion especially for large datasets. If you are going to use a very large dataset and need to be able to access as an array, then I would use a hybrid between the two. The javascript object would be used for direct access to the object. A class-like implementation would be preferred for that, but without using oo, the code would look something like this:
var data = [];
var keys = {};
function addItem(name, itemCode, stock){
var newItem = new item(name, itemCode, stock);
if(keys[itemCode] === undefined){
data.push(newItem);
keys[itemCode] = data.length - 1;
}
}
This implementation also gets complicated if you are going to modify the array more than just adding elements
You can map the data array to itemCodes and see if it includes the itemCode of the new item, and if so return an empty object for your constructor. Then in your addItem function you can choose not to add the object to the array if the object is empty.
var item = function(name,itemCode,stock){
if (data.map(i => i.itemCode).includes(itemCode)) {
alert("This item has a duplicate itemCode");
return this;
}
this.name = name;
this.itemCode = itemCode;
this.stock = stock;
}
var data = [];
function addItem(name,itemCode,stock){
var Newitem = new item(name,itemCode,stock);
if (Newitem.name) data.push(Newitem); // check if an object was created with properties
}
addItem('BlueTee',100,50);
addItem('Yellow tee',101,100);
addItem('BrownTee',102,120);
addItem('RedTee',100,70); // this won't be added because of duplicate itemCode
console.log(data); // only contains BlueTee, Yellow tee, and BrownTee objects

Why Javascript object didn't change?

Can someone explain me this strange js behavior ?
All of this is in AngularJS.
I have helper function in my main app.js to simply return element from an array by its id:
var MyLib = MyLib || {};
MyLib.helpers = {
find: function(needle, stack) {
for (var i = 0; i < stack.length; i++) {
if(stack[i]._id === needle)
return stack[i];
}
return false;
}
}
Then I have factory and function to handle database change:
// categories are grabbed from db
var categories = [some array of objects];
// change is object returned from database that has all info about object as well as new object itself
function handleChange(change) {
var _category = MyLib.helpers.find(change.id, categories);
// if deleted, that part is ok
if(change.deleted) {
var idx = categories.indexOf(_category);
if(idx !== -1) {
categories.splice(idx, 1);
}
} else {
// if updated that part is weird
if(_category) {
_category = change.doc;
}
// if newly added that part is ok
else {
categories.push( angular.copy(change.doc) );
}
}
}
Why when I try to update element grabbed from categories array doesn't update in categories array ?
// categories ARE NOT updated after this
_category = change.doc;
and only when I refer to categories by index like this:
// categories ARE updated after this although _category is returned from this array by index (find function)
var idx = categories.indexOf(_category);
categories[idx] = change.doc;
I don't understand this...
You are overwriting the variable with a new value and any reference to prior value is gone.
Instead of overwriting the original object value with a new object you could update the existing object using angular.extend()
angular.extend(_category, change.doc);
I didn't analyze everything, but you should always have dot notation.
_category pass by value, and will not change when 'MyLib.hel ...' is changed
var _category = MyLib.helpers.find(change.id, categories);
something.category pass by reference, and will be changed when 'MyLib.hel ...' is changed
var something.category = MyLib.helpers.find(change.id, categories);

Knockoutjs arrayFilter multiple dropdowns

I have a question regarding arrayFilter in knockoutjs, how would i go about filtering my list with 2 different dropdowns which whould be related so if i have choosen 1 type of building but no area i should be shown all of that type of buildings, however if i where to choose a building option and an area option the filtering should account for that, ive been working on a prototype now for 2 days but cant figure out how to return the correct item in the arrayfilter.
http://jsfiddle.net/vGg2h/138/
Currently i made all my models and pastin in data via the viewmodel, and i got a filtered list hooked up, however i dont understand how to return the correct item back through the foreach filter and the arrayFilter, this is where it gets abit blurry.
self.filteredList = ko.computed(function () {
var filters = [];
filters.push(self.selectedBuilding());
filters.push(self.selectedArea());
var currentList = [];
ko.utils.arrayForEach(filters, function (filter) {
if (typeof filter !== "undefined") {
ko.utils.arrayFilter(self.products(), function (item) {
if (filter.id == item.areaId || filter.value == item.buildingId) {
currentList.push(item);
}
});
}
});
return currentList;
});
Thanks in advance for any answers!
You have two problems:
you are not correctly using ko.utils.arrayFilter: you have to return true or false depending on whether and item should be included in the end result or not. So you should not build your result inside the arrayFilter
you are always starting form the full list and not applying the filters one after the other, but incorrectly build the result in the arrayFilter which lead to combining your filters with OR and not with AND as you originally wanted
Your fixed code would like this:
self.filteredList = ko.computed(function () {
var filters = [];
filters.push(self.selectedBuilding());
filters.push(self.selectedArea());
var currentList = self.products();
ko.utils.arrayForEach(filters, function (filter) {
if (typeof filter !== "undefined") {
currentList = ko.utils.arrayFilter(currentList, function (item) {
if (filter.id == item.areaId || filter.value == item.buildingId) {
return true;
}
});
}
});
return currentList;
});
Demo JSFiddle
Two better see the AND filtering with reusing the same list you can rewrite your code to do the filtering in two separate steps:
self.filteredList = ko.computed(function () {
var currentList = self.products();
if (self.selectedBuilding())
{
currentList = ko.utils.arrayFilter(currentList, function(item) {
return self.selectedBuilding().value == item.buildingId;
});
}
if (self.selectedArea())
{
currentList = ko.utils.arrayFilter(currentList, function(item) {
return self.selectedArea().id == item.areaId;
});
}
return currentList;
});
In this code it is more clearer that you start from the full list and then apply the different filters one by one, further and further filtering the original list.
Demo JSFiddle
Note: if you initially want to start with an empty list (like in your original code) then you can just return an empty array if all of your filters are empty:
self.filteredList = ko.computed(function () {
if (!self.selectedBuilding() && !self.selectedArea())
return [];
//...
};
Demo JSFiddle.

How to filter `objects` by it's value

In my angular controller, I would like to filter and assign some object with true value. i am trying to iterate using angular.forEach but i am getting all object as result instead of getting the truthy object.
here is my code :
$scope.splash.$promise.then(function (result) {
$scope.allApps = result; //50 apps.
// splashAppsHandler();
$scope.splashApps = angular.forEach( $scope.allApps, function (app) {
return app.projects.project.splash === true; //only 5 apps
});
console.log($scope.splashApps); //getting all 50 apps!?
});
What is the correct way to do it?
You need to store truthy objects with in an array or object. Currently you are not doing inside angular forEach.
$scope.truthyObjects = [];
$scope.splash.$promise.then(function (result) {
$scope.allApps = result; //50 apps.
// splashAppsHandler();
$scope.splashApps = angular.forEach( $scope.allApps, function (app) {
if(app.projects.project.splash === true) {
$scope.truthyObjects.push(app); // save truthy object
}
});
console.log($scope.splashApps); //getting all 50 apps!?
});

Check if an element exists in a object

I have a set of radio buttons, when a radio button is selected the element is pushed into an object.
Then I need to take the value of the elements in the object and then push them into an array, if they are not already in the array.
My problem is that I keep getting duplicates or more in my array of each of the values with this function because I am not checking correctly if they exists.
How can I check if the element already exists in my array and then exclude it from being added?
_this.selected = {};
_this.selectedArray = [];
//loop through the object
angular.forEach(_this.selected, function ( item ){
//if it is not the first time the array is getting data loop through the array
if(_this.selectedArray.length > 0) {
_this.selectedArray.forEach(function (node){
//check to see if the item already exists-- this is where it is failing
//and running the loop too many times
if(node.id !== item.id){
_this.selectedArray.push(item);
}
});
} else {
_this.selectedArray.push(share);
}
});
You can use additional hash to check if you have already added item to array.
_this.selected = {};
_this.selectedArray = [];
_this.selectedHash = {};
//loop through the object
angular.forEach(_this.selected, function ( item ){
if(_this.selectedHash[item.id]) { return; }
_this.selectedArray.push(item);
_this.selectedHash[item.id] = 1;
});
Have you tried jQuery's inArray? http://api.jquery.com/jquery.inarray
It works the same as the indexOf method on String.
You could try if $.inArray(node, selectedArray) == -1 // element is not in the array
You can run this function on that array to reduce it to unique values rather than applying complex code to check whether the array had an element or not
var getOnlyUniqueValuesInArray = function(arrayObj) {
return arrayObj.reduce(function(a, b) {
if (a.indexOf(b) < 0) a.push(b);
return p;
}, []);
};
Hi that should helps
var app = angular.module('app', []);
app.controller('firstCtrl', function($scope){
var app = angular.module('app', []);
app.controller('firstCtrl', function($scope) {
_this.selected = {};
_this.selectedArray = [];
//loop through the object
angular.forEach(_this.selected, function(item) {
//if it is not the first time the array is getting data loop through the array
if (_this.selectedArray.length > 0) {
var canAdd = true;
_this.selectedArray.forEach(function(node) {
//do not add iny any of node.id will be equal to item.id
if (node.id == item.id) {
canAdd = false;
}
});
if(canAdd){
_this.selectedArray.push(item);
};
} else {
_this.selectedArray.push(share);
}
});
})
});

Categories

Resources