Separate category item angularJS - javascript

How to list items in AngularJS and separate them by category, something like this:
<h3>Products</h3>
<div ng-repeat="item in products">
<div>
{{item.category}}
</div>
<p>
{{item.name}}
</p>
<p>
{{item.price}}
</p>
</div>
$scope:
$scope.products = [
{
name:"product1",
price:"450",
category:"cat1"
},
{
name:"product2",
price:"450",
category:"cat2"
},
{
name:"product3",
price:"450",
category:"cat1"
}
];
I want it to look something like this:
cat1
--->product1
--->product3
cat2
--->product2
...
Please help!

See [fiddle])(http://jsfiddle.net/Lvc0u55v/2846/)
I did some formatting to message the data in desired format.
$scope.productCategories = {};
for (var i = 0; i < products.length; i++) {
if ($scope.productCategories[products[i].category] == undefined)
$scope.productCategories[products[i].category] = [];
$scope.productCategories[products[i].category].push({
name: products[i].name,
price: products[i].price
});
}
Html Formatting is off, but I hope this gives you an idea

you can use groupBy filter in ng-repeat. you should add groupBy filter dependency in your app.
var app = angular.module("app",['angular.filter']);
app.controller("ctrl" , function($scope){
$scope.products = [ { name:"product1", price:"450", category:"cat1" }, { name:"product2", price:"450", category:"cat2" }, { name:"product3", price:"450", category:"cat1" } ];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>
<div ng-app="app" ng-controller="ctrl" class="panel-group" id="accordion">
<h3>Products</h3>
<div ng-repeat="(key,value) in products | groupBy: 'category'">
<div>
{{key}}
</div>
<div ng-repeat="item in value">
<p>
{{item.name}}
</p>
<p>
{{item.price}}
</p>
</div>
</div>
</div>

Related

Angular filter on object property inside an array

I am having an array of objects inside the $scope. The object has the name and 'attributes' property of which the attributes is an object. I have a text field which I need to bind to a model which should be used to filter the state based on either the name or noOfCitizens. However, the below code is not filtering the items. Where I am going wrong.
I am working with Angularjs 1.5.8 version
//Inside the controller
$scope.states=[];
var mp = {};
mp.name = "MP";
mp.attributes= {
"name":"MP",
"noOfCitizens":"~ 900000"
};
var ts = {};
ts.name = "TS";
ts.attributes= {
"name":"TS",
"noOfCitizens":"~ 8000"
};
$scope.states.push(mp);
$scope.states.push(ts);
<!-- Inside my html page -->
<div style="margin-left: 10px">
<input type="text" ng-model="state.attributes['name']" placeholder="filter">
</div>
<div class="col-lg-3" ng-repeat="state in states | filter:state.attributes['name']">
<h2>{{state.name}}</h2>
<ul>
<li>Name: {{state.attributes['name']}}</li>
<li>No Of Citizens: {{state.attributes['noOfCitizens']}}</li>
</ul>
</div>
Change your ng-model directive and the option passed to the filter pipe as follows,
ng-model="ctrl.stateFilter"
ng-repeat="state in ctrl.states | filter : ctrl.stateFilter"
Check the below code snippet.
angular
.module('demo', [])
.controller('DefaultController', DefaultController);
function DefaultController() {
var vm = this;
vm.states = [];
var mp = {
name: "MP",
attributes: {
"name": "MP",
"noOfCitizens": "~ 900000"
}
};
var ts = {
name: "TS",
attributes: {
"name": "TS",
"noOfCitizens": "~ 8000"
}
};
var vs = {
name: "VS",
attributes: {
"name": "VS",
"noOfCitizens": "~ 8000"
}
};
vm.states.push(mp);
vm.states.push(ts);
vm.states.push(vs);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demo">
<div ng-controller="DefaultController as ctrl">
<div style="margin-left: 10px">
<input type="text" ng-model="ctrl.stateFilter" placeholder="filter">
</div>
<div class="col-lg-3" ng-repeat="state in ctrl.states | filter : ctrl.stateFilter">
<h2>{{state.name}}</h2>
<ul>
<li>Name: {{state.attributes.name}}</li>
<li>No Of Citizens: {{state.attributes.noOfCitizens}}</li>
</ul>
</div>
</div>
</div>

data-ng-repeat with different tags in Angular

There is the following variable in Angular controller:
$scope.items = [
{ title: 'x', type: 'x'},
{ title: 'y', type: 'y'}
];
You can see only 2 items in array, but they will be more. So, I need to 'render' this array in HTML. I can use ng-repeat Angular directive, but there is some problem: if item has type 'x' I must render for it, if y - for it. How can I do it? Thanks in advance!
Place a :filter in the ng-repeat, like this:
var app = angular.module('myapp', []);
app.controller('myctrl', function($scope) {
$scope.items = [{
title: 'x',
type: 'x'
}, {
title: 'y',
type: 'y'
}, , {
title: 'another x',
type: 'x'
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp" ng-controller="myctrl">
<div>Only items of type 'x':</div>
<ul>
<li ng-repeat="item in items | filter: {type: 'x'} ">{{item.title}}</li>
</ul>
</div>
Use a commbination of ng-repeat and ng-switch:
angular.module('myApp', [])
.controller('myCtrl', function($scope) {
$scope.items = [
{ title: "TestX", type: "x" },
{ title: "TestY", type: "y" }
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="item in items">
{{ item.title }}
<div ng-switch="item.type">
<div ng-switch-when="x">
HTML for type x
</div>
<div ng-switch-when="y">
HTML for type y
</div>
</div>
</div>
</div>
You can also use ng-hide which hides element if expression is true
<div ng-repeat="item in items" >
<div ng-hide="item.type == 'y'">
{{ item.type }}
</div>
<div ng-hide="item.type == 'x'">
{{ item.type }}
</div>
</div>
If you want to render only for item type x then can user 'filter' in ng-repeat or can use ng-if
<div ng-repeat="item in items">
<div ng-if="item.type==='x'">
<p>Item for type x</p>
</div>
</div>

Using another scope object values within the ng-repeat of some other scope object

I have set up a fiddle to explain my question well. I would like to display the names from the $scope.gem inside ng-repeat [only one name for each ng-repeat and don't loop all] of $scope.knobItems without extending the knobItems scope. I want this to be made possible by maintaining the exact structure of controller as it is now. I am new to angular. I just wanna know if this is possible in angular and if is a good practice.
view
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="knobs in knobItems">
<div ng-repeat="(key, value) in knobItems.nums">{{value.knobTitle}} : {{value.knobColor}}
<div ng-bind="gem[0].name"></div>
</div>
</div>
</div>
</div>
controller
var ngMod = angular.module("myapp", []);
ngMod.controller("Mycont", function ($scope) {
$scope.knobItems = {};
$scope.knobItems.nums = [{
knobTitle: "Company Profile",
knobColor: "#f46607"
}, {
knobTitle: "Deals left This Month",
knobColor: "#ffcc00"
}, {
knobTitle: "Pricelist",
knobColor: "#f40787"
}, {
knobTitle: "Pictures",
knobColor: "#a1b80a"
}, {
knobTitle: "Videos",
knobColor: "#14b9d6"
}];
$scope.gem = [{
name: "Thomas"
}, {
name: "Sebastian"
}, {
name: "June"
}, {
name: "Yuvan"
}];
});
intended output
Easy fix: fiddle
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="knobs in knobItems">
<div ng-repeat="(key, value) in knobItems.nums">{{value.knobTitle}} : {{value.knobColor}}
<div ng-bind="gem[$index].name"></div>
</div>
</div>
</div>
</div>
The output in you fiddle is exactly the same without the first ng-repeat: http://jsfiddle.net/2nrbrfxL/
Going by you description rather than you code:
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="knobs in knobItems">
<div ng-repeat="(key, value) in knobs">{{value.knobTitle}} : {{value.knobColor}}
<div ng-repeat="gemItem in gem">{{gemItem.name}}</div>
</div>
</div>
</div>
</div>
http://jsfiddle.net/p2fuq2du/
<div ng-app="myapp">
<div ng-controller="Mycont">
<div ng-repeat="(key, value) in knobItems.nums">{{value.knobTitle}} : {{value.knobColor}}
<div ng-bind="gem[key].name"></div>
</div>
</div>
</div>

multidimensional array in angular

I have a multidimensional array from an API. Is it possible to programatically loop through the array?
{
success: true,
categories: [{
cat_id: "2",
name: "This is category One",
description: null,
photo_url: "/img/test.png",
order: "1",
items: [{
item_id: "1",
title: "Desk",
item_url: "/690928460",
photo_url: "/desk.png",
}, {
item_id: "2",
title: "Chair",
item_url: "/18882823",
photo_url: "/chair.png",
},
}]
}]
}
My controller looks like this:
myApp.controller('items', function($scope, $http, $location, Data) {
var apiUrl = '/api/items';
$http.get(apiUrl).
success(function(data) {
$scope.data = Data;
$scope.allData = data;
});
$scope.changeView = function(view) {
$location.path(view);
}
});
Angular index file just has: <div ng-view=""></div>
View file
<div class="scrollable categories-container animated-fast slideInUp">
<div class="container categories">
<div class="row" ng-repeat="categories in allData">
<div class="col-xs-6" ng-repeat="category in categories">
<div class="items">
<div class="title">
{{ category.name }}
</div>
</div>
</div>
</div>
</div>
</div>
I can loop through the category names fine, but when trying to return items for EACH category I don't understand the logic behind it...
I would suggest some simple nested for loops, as for each gives rise to more complexity.
As I'm not sure what you want to do with the data let's just create an array of all item names and one of all category names:
Within your success function:
var items = [], categories = []
for(var i = 0; i < data.categories.length;i++){
categories.push(data.categories[i].name);
for(var j = 0; j < data.categories[i].items.length;j++){
items.push(data.categories[i].items[j].name);
}
}
console.log(categories);
console.log(items);
EDIT:
Completely missed your html code somehow, here is my solution:
<div class="scrollable categories-container animated-fast slideInUp">
<div class="container categories">
<div class="col-xs-6" ng-repeat="category in allData.categories">
<div class="items">
<div class="title">
{{ category.name }}
</div>
</div>
</div>
</div>
</div>
EDIT 2:
As to your comment:
If you want to select the secondary view's contents(ie the items) based on the selection of a category I would suggest a ng-click attribute. A directive could be used but isn't necessary:
<div class="scrollable categories-container animated-fast slideInUp">
<div class="container categories">
<div class="col-xs-6" ng-repeat="category in allData.categories">
<div class="title" ng_click="selected_category = category">
{{ category.name }}
</div>
</div>
<div class="col-xs-6" ng-repeat="item in selected_category.items">
<div class="title">
{{ item.name }}
</div>
</div>
</div>
</div>
So when your categories data is loaded the first ng-repeat is populated with the categories. Each div with class title will have a function called on click which will make the selected_category object equal the selected category.
This will then cause the second view to be populated with all the items in the selected category by Angular's two way bind.

Avoiding Dupes when pushing values from form to array in AngularJS

I'm having problems avoiding dupes with my code. Here is a simplified example. I know the problem is in the array object being a reference of the same scope variable, but what is the best way to avoid it?
<div ng-app="myApp">
<div ng-controller="myCtrl">
<input type="text" ng-model="item" />
<div ng-repeat="item in items">
{{ item }}
</div>
<button ng-click="save()">Save</button>
</div>
</div>
<script>
angular.module('myApp', []).
controller('myCtrl', function ($scope) {
$scope.items = [];
$scope.save = function() {
$scope.items.push($scope.item);
}
});
</script>
Here is a fiddle that demonstrates the problem:
http://jsfiddle.net/u8Fuk/8/
Use track by syntax to fix this problem.
<div ng-repeat="item in items track by $index">
{{ item }}
</div>
Here is a fiddle.
Depends on what your goal is.
If you want to allow for duplicate values you need to change the code a bit as each item in the ngRepeat has to have a unique id. See the track by section here.
That would work like this:
<div ng-app="myApp">
<div ng-controller="myCtrl">
<input type="text" ng-model="item" />
<div ng-repeat="item in items">
{{ item.value }}
</div>
<button ng-click="save()">Save</button>
</div>
</div>
<script>
angular.module('myApp', []).
controller('myCtrl', function ($scope) {
$scope.items = [];
$scope.save = function() {
$scope.items.push({value:$scope.item});
}
});
</script>
See the updated fiddle here.
If you don't want to allow for the same values you need to search for it.
<div ng-app="myApp">
<div ng-controller="myCtrl">
<input type="text" ng-model="item" />
<div ng-repeat="item in items">
{{ item }}
</div>
<button ng-click="save()">Save</button>
</div>
</div>
<script>
angular.module('myApp', []).
controller('myCtrl', function ($scope) {
$scope.items = [];
$scope.save = function() {
var found = $scope.items.reduce(function(previous, i){
if ($scope.item === i) return true;
return previous;
}, false);
if (found){
alert('duplicate value');
}
else{
$scope.items.push($scope.item);
}
}
});
</script>
See the updated fiddle here.

Categories

Resources