md-select with recursive options - angularjs

I am trying to iterate through an array of categories with subcategories.
The problem. I have this array of categories:
$scope.categories = [{
"_id": 1,
"name": "Cat 1",
"categories": {
"_id": 11,
"name": "Cat 11",
"categories": {
"_id": 111,
"name": "Cat 111",
"categories": null
}
}
}, {
"_id": 2,
"name": "Cat 2",
"categories": null
}, {
"_id": 3,
"name": "Cat 3",
"categories": null
}];
As you can see, is an array of objects with subcategories, so I know that I need a recursive solution.
I need to show all the categories into a md-select (it is not necesary group it, but it will be great) and I am trying this:
<md-input-container class="md-block">
<label>Categories</label>
<md-select ng-model="selectedCategory">
<md-option ng-value="category._id" ng-repeat-start="category in categories">{{category.name}}</md-option>
<span ng-repeat-end ng-include="'subcategories'" ng-if="category.categories"></span>
</md-select>
</md-input-container>
<script type="text/ng-template" id="subcategories">
{{category.name}}
<md-option ng-value="category._id" ng-repeat-start="category in category.categories">{{category.name}}</md-option>
<span ng-repeat-end ng-include="'subcategories'" ng-if="category.categories"></span>
It works partially, but it is not the result expected.
What I want? Something like this
What I have? This code
Tell me if need more details.
Thanks

You can simply flatten your list and style elements by their nesting level.
angular
.module('app', ['ngMaterial'])
.controller('AppController', function($scope) {
$scope.categories = [{
"_id": 1,
"name": "Cat 1",
"categories": [{
"_id": 11,
"name": "Cat 11",
"categories": [{
"_id": 111,
"name": "Cat 111",
"categories": null
}]
}]
}, {
"_id": 2,
"name": "Cat 2",
"categories": null
}, {
"_id": 3,
"name": "Cat 3",
"categories": null
}];
$scope.flattenCategories = flatten($scope.categories, 0);
function flatten(categories, level) {
var flat = [];
for (var i = 0, n = categories.length, category; category = categories[i]; i++) {
flat.push({
_id: category._id,
name: category.name,
level: level
});
if (category.categories) {
flat = flat.concat(flatten(category.categories, level + 1));
}
}
return flat;
}
});
.subcategory-0 .md-text {
margin-left: 0;
}
.subcategory-1 .md-text {
margin-left: 8px;
}
.subcategory-2 .md-text {
margin-left: 16px;
}
.subcategory-3 .md-text {
margin-left: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.11/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.11/angular-animate.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.11/angular-aria.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.11/angular-messages.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.4/angular-material.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/1.1.0/angular-material.min.css">
<div ng-app="app" ng-controller="AppController">
<form name="myForm">
<md-input-container class="md-block">
<label>Categories</label>
<md-select ng-model="selectedCategory" name="myCategory">
<md-option ng-class="'subcategory-' + category.level" ng-value="category._id" ng-repeat="category in flattenCategories track by category._id">{{ category.name }}</md-option>
</md-select>
<!-- <pre ng-bind="flattenCategories | json"></pre> -->
</md-input-container>
</form>
</div>

Related

AngularJS displays only elements that meet a certain condition

in my ng-repeat list I am displaying object elements from an object array $scope.toBuy:
$scope.toBuy=[
cookies={
name:'cookies',quantity:0,bought:false
},
water={
name:'water',quantity:0,bought:false
},
bananas={
name:'bananas',quantity:0,bought:false
},
milk={
name:'milk',quantity:0,bought:false
},
coconut={
name:'coconut',quantity:0,bought:false
}
];
and I initialize all element's bought field to false. How do I display in a ng-repeat list that only shows elements that have false value in their bought field? I tried this:
<ul>
<li ng-repeat="item in toBuy | filter:{item.bought===false }">Buy 10 {{item.quantity}} {{item.name}} <button class="btn btn-default" ng-click="btnOnClick(item.name)"> Bought</button></li>
</ul>
but none of the elements displayed when the page is loaded. If I removed the filter, the whole list displays, which means I applied the filter wrong.
You are using invalid javascript object syntax {item.bought===false }
Change to
ng-repeat="item in toBuy | filter:{bought:false }"
DEMO
Your JSON is not a valid JSON.
Try this valid JSON :
[{
"name": "cookies",
"quantity": 0,
"bought": true
}, {
"name": "water",
"quantity": 0,
"bought": true
}, {
"name": "bananas",
"quantity": 0,
"bought": true
}, {
"name": "milk",
"quantity": 0,
"bought": false
}, {
"name": "coconut",
"quantity": 0,
"bought": false
}]
Working demo :
var myApp = angular.module('myApp',[]);
myApp.controller('MyCtrl', function($scope) {
$scope.toBuy=[{
"name": "cookies",
"quantity": 0,
"bought": true
}, {
"name": "water",
"quantity": 0,
"bought": true
}, {
"name": "bananas",
"quantity": 0,
"bought": true
}, {
"name": "milk",
"quantity": 0,
"bought": false
}, {
"name": "coconut",
"quantity": 0,
"bought": false
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
<ul>
<li ng-repeat="item in toBuy | filter : {bought:false}">Buy 10 {{item.quantity}} {{item.name}} <button class="btn btn-default" ng-click="btnOnClick(item.name)"> Bought</button></li>
</ul>
</div>
Use ng-if (or ng-show):
<div ng-repeat="item in toBuy">
<div ng-if="item.bought===false">
Buy 10 {{item.quantity}} {{item.name}}
</div>
</div>
Try this:
<li ng-repeat="item in toBuy | filter:item.bought==false">
Or
<li ng-repeat="item in toBuy | filter:{bought:false}">
Will work, the second is a better way to achieve this.

ng-repeat filter by one key and two value

This is my JSON data:
[
{
"name": "elin",
"family": "kinoian"
},
{
"name": "simon",
"family": "santos"
},
{
"name": "sara",
"family": "pinki"
},
{
"name": "emin",
"family": "richard"
}
]
As you can see,I have 2 key in each row "name" and "family.
This is my ng-repeat filtering by json object "search":
<li ng-repeat="membr in familyMember| filter:search">
<span> {{membr.name}} - {{membr.family}}</span>
</li>
And these are my inputs for filtering:
By name: <input type="text" ng-model="search.name1">
and <input type="text" ng-model="search.name2">
By family: <input type="text" ng-model="search.family">
I need the rows which name is "elin" and "sara". I`m looking for "AND Condition" in filtering. How can I do that?
First of all, no, you're not looking for an AND condition, but for an OR. Indeed, a family member can't be named "elin" and "sara" at the same time.
Now, if you read the documentation for the filter filter, you'll see that it accepts a function as argument, which must return a truthy value if the value is accepted, and a truthy value if it's rejected. So all you need is
ng-repeat="member in familyMember| filter:isAccepted">
and
$scope.isAccepted = function(member) {
return member.name === $scope.search.name1 || member.name === $scope.search.name2;
}
You need to use a custom filter with OR condition.
$scope.nameFilter = function(member) {
var result = (member.name == $scope.membr.name1) ||
(member.name == $scope.membr.name2) ||
(member.family == $scope.membr.family);
return result;
};
DEMO
var myApp = angular.module('myApp', []);
myApp.controller("MyCtrl", ['$scope', function($scope) {
$scope.familyMember = [{
"name": "elin",
"family": "kinoian"
}, {
"name": "simon",
"family": "santos"
}, {
"name": "sara",
"family": "pinki"
}, {
"name": "emin",
"family": "richard"
}];
$scope.nameFilter = function(member) {
var result = (member.name == $scope.membr.name1) ||
(member.name == $scope.membr.name2) ||
(member.family == $scope.membr.family);
return result;
};
}]);
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.4.7" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="MyCtrl">
By name:
<input type="text" ng-model="membr.name1" > and
<input type="text" ng-model="membr.name2"> By family:
<input type="text" ng-model="membr.family">
<li ng-repeat="membr in familyMember| filter:nameFilter">
<span> {{membr.name}} - {{membr.family}}</span>
</li>
</div>
</body>
</html>
Try this working demo :
var app = angular.module('myApp',[]);
app.controller('mainCtrl', function($scope) {
$scope.familyMember = [
{
"name": "elin",
"family": "kinoian"
},
{
"name": "simon",
"family": "santos"
},
{
"name": "sara",
"family": "pinki"
},
{
"name": "emin",
"family": "richard"
}
];
$scope.search = function(membr) {
return membr.name === $scope.search.name1 || membr.name === $scope.search.name2;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='myApp' ng-controller='mainCtrl'>
name1: <input type="text" ng-model="search.name1">
name2: <input type="text" ng-model="search.name2"><br><br>
<li ng-repeat="membr in familyMember | filter:search">
<span> {{membr.name}} - {{membr.family}}</span>
</li>
</div>

AngularJS sorting by field value

What I am trying to do is sort some data by field value.
$scope.testarr = [{"id":"1","name":"coffee"},
{"id":"2","name":"tea"},
{"id":"3","name":"coffee"},
{"id":"4","name":"ice coffee"}]
in the html file i have select box and 3 options called coffee, tea and ice coffee,
if i select coffee should be sorted like this
$scope.testarr = [{"id":"1","name":"coffee"},
{"id":"3","name":"coffee"},
{"id":"2","name":"tea"},
{"id":"4","name":"ice coffee"}]
if i select tea should be sorted like this
$scope.testarr = [
{"id":"2","name":"tea"},
{"id":"1","name":"coffee"},
{"id":"3","name":"coffee"},
{"id":"4","name":"ice coffee"}]
i'm trying to use order by but somehow it does't work
<div ng-repeat="item in testarr | orderBy: 'name'">
{{item.id}} ------ {{item.name}}
</div>
It does seem to work. Ensure that your ng-repeat has access to $scope.testarr (i.e. it is being declared on your $scope in the correct controller or directive.
angular.module('app', [])
.controller('ctrl', function($scope) {
$scope.testarr = [{
"id": "1",
"name": "coffee"
}, {
"id": "2",
"name": "tea"
}, {
"id": "3",
"name": "coffee"
}, {
"id": "4",
"name": "ice coffee"
}];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="ctrl">
<div ng-repeat="item in testarr | orderBy: 'name'">
{{item.id}} ------ {{item.name}}
</div>
</div>
</div>

Update <select> tag inside ng-if in angularjs

I would like to update the list of states on selection of country. I have researched a bit into this where it was recommended to use $parent as ng-if does not work on controller scope.But that too is not working for me.
Can someone please help me understand how to get the values into state select control.
Also I would also like to know what if there are multiple ng-if in my HTML. (again nested $parent.$parent.$parent... is not working)
Plunker Link : Plunker Link
"use strict";
var app = angular.module("app", []);
function CountriesController($scope) {
$scope.condition = true;
$scope.countries = [{
"name": "USA",
"id": 1
},{
"name": "Canada",
"id": 2
}];
$scope.states = [{
"name": "Alabama",
"id": 1,
"countryId": 1
}, {
"name": "Alaska",
"id": 2,
"countryId": 1
}, {
"name": "Arizona",
"id": 3,
"countryId": 1
}, {
"name": "Alberta",
"id": 4,
"countryId": 2
}, {
"name": "British columbia",
"id": 5,
"countryId": 2
}];
$scope.updateCountry = function(){
$scope.availableStates = [];
angular.forEach($scope.states, function(value){
if(value.countryId == $scope.country.id){
$scope.availableStates.push(value);
}
});
}
}
<!DOCTYPE html>
<html data-ng-app="app">
<head>
<script data-require="angular.js#1.1.5" data-semver="1.1.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body data-ng-controller="CountriesController">
<div ng-if="condition">
<select data-ng-model="country" data-ng-options="country.name for country in countries" data-ng-change="updateCountry()">
<option value="">Select country</option>
</select>
<br>
<select data-ng-model="state" data-ng-options="state.name for state in availableStates">
<option value="">Select state</option>
</select>
<br> Country: {{country}}
<br> State: {{state}}
</div>
</body>
</html>
Instead of making a separate list, you can use your country list by filtering
filter: {countryId: $parent.country.id}
"use strict";
var app = angular.module("app", []);
function CountriesController($scope) {
$scope.condition = true;
$scope.countries = [{
"name": "USA",
"id": 1
},{
"name": "Canada",
"id": 2
}];
$scope.states = [{
"name": "Alabama",
"id": 1,
"countryId": 1
}, {
"name": "Alaska",
"id": 2,
"countryId": 1
}, {
"name": "Arizona",
"id": 3,
"countryId": 1
}, {
"name": "Alberta",
"id": 4,
"countryId": 2
}, {
"name": "British columbia",
"id": 5,
"countryId": 2
}];
$scope.updateCountry = function(){
$scope.availableStates = [];
angular.forEach($scope.states, function(value){
if(value.countryId == $scope.country.id){
$scope.availableStates.push(value);
}
});
}
}
<!DOCTYPE html>
<html data-ng-app="app">
<head>
<script data-require="angular.js#1.1.5" data-semver="1.1.5" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body data-ng-controller="CountriesController">
<div ng-if="condition">
<select data-ng-model="country" data-ng-options="country.name for country in countries" data-ng-change="">
<option value="">Select country</option>
</select>
<br>
<select data-ng-model="state" data-ng-options="state.name for state in states | filter:{countryId: country.id}:true">
<option value="">Select state</option>
</select>
<br> Country: {{country}}
<br> State: {{state}}
</div>
</body>
</html>
Here is simplest way to init selected option:
for blank form, just init with option value that you want (don't forget the double single quotes)
<select ng-model="$ctrl.data.userlevel" ng-init="$ctrl.data.userlevel='0'">
<option value="0">User</option>
<option value="1">Admin</option>
</select>
for loaded data form, just init using that loaded model data, like below:
<select ng-model="$ctrl.data.userlevel" ng-init="$ctrl.data.userlevel=''+$ctrl.data.userlevel">
<option value="0">User</option>
<option value="1">Admin</option>
</select>
i think, init value should be string. so they need to concat with double single quotes.

Ionic responsive grid doesn't work

I created a responsive grid in Ionic which doesn't work properly. The Grid is not responsive. So it isn't automatically adjusted on different screen size and set no linebreak if I add many Buttons or delete these to the/from the system. Either they merge into each other or all the buttons are in a column below the each other on small screens. How can i solve this?
I add or delete all the buttons in a JSON-File. From there I parse the Buttons in to the system.
JSON: 7 Buttons
[
{
"_comment": "Games",
"type": "button",
"id": "entertainmentButton",
"icon": "ion-film-marker",
"name": "Game and entertainment",
"topage": "servicePage.html",
"color": "white",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"backgroundcolor": "#0066FF",
"font-size": "26px"
},
{
"_comment": "Logo",
"type": "button",
"id": "MainPageLogo",
"icon": "",
"image": "../img/icon/logo_moenchsweiler.png",
"name": "second link",
"topage": "",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"color": "",
"backgroundcolor": "",
"font-size": ""
},
{
"_comment": "Logo",
"type": "button",
"id": "MainPageLogo",
"icon": "",
"image": "../img/icon/logo_moenchsweiler.png",
"name": "second link",
"topage": "",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"color": "",
"backgroundcolor": "",
"font-size": ""
},
{
"_comment": "Logo",
"type": "button",
"id": "MainPageLogo",
"icon": "",
"image": "../img/icon/logo_moenchsweiler.png",
"name": "second link",
"topage": "",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"color": "",
"backgroundcolor": "",
"font-size": ""
},
{
"_comment": "Logo",
"type": "button",
"id": "MainPageLogo",
"icon": "",
"image": "../img/icon/logo_moenchsweiler.png",
"name": "second link",
"topage": "",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"color": "",
"backgroundcolor": "",
"font-size": ""
},
{
"_comment": "Logo",
"type": "button",
"id": "MainPageLogo",
"icon": "",
"image": "../img/icon/logo_moenchsweiler.png",
"name": "second link",
"topage": "",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"color": "",
"backgroundcolor": "",
"font-size": ""
},
{
"_comment": "Logo",
"type": "button",
"id": "MainPageLogo",
"icon": "",
"image": "../img/icon/logo_moenchsweiler.png",
"name": "second link",
"topage": "",
"function": "OpenLink()",
"controller": "OpenLinkCtrl",
"color": "",
"backgroundcolor": "",
"font-size": ""
}
]
JavaScript:
var myApp = angular.module('starter', []);
myApp.config(['$sceDelegateProvider', function($sceDelegateProvider) {
$sceDelegateProvider.resourceUrlWhitelist([
'self',
''
]);
}]);
myApp.controller('generateHTMLCtrl', function ($scope, $http, $compile, $interpolate, $templateCache) {
$http.get('myjsonfile.json').success(function (data) {
for(var i in data){
var interpolated = $interpolate($templateCache.get("tpl").trim())(data[i]);
angular.element(document.querySelector("#loadhere")).append($compile(interpolated)($scope));
}
});
});
myApp.controller("OpenLinkCtrl", function ($scope) {
$scope.OpenLink = function () {
alert("Link open");
}
});
HTML:
<body ng-app="starter" class="padding" style="text-align: center">
<div class="row responsive-md" ng-controller="generateHTMLCtrl" id="loadhere"></div>
<script type="text/ng-template" id="tpl">
<div class="col">
<a style="color:{{color}}; background-color:{{backgroundcolor}} " id="{{id}}" class="{{type}}" href="{{topage}}" ng-controller="{{controller}}" ng-click="{{function}}"> <i class="{{icon}}"><br></i>{{name}}</a>
</div>
</script>
</body>
What do I need to modify in HTMl-code that the Grid is responsive?
Edit:
It should look like here, e.g:
<div class="row responsive-sm">
<div class="col">
<button style="width: 100px; height: 100px">Test</button>
<button style="width: 100px; height: 100px">Test</button>
<button style="width: 100px; height: 100px">Test</button>
<button style="width: 100px; height: 100px">Test</button>
<button style="width: 100px; height: 100px">Test</button>
<button style="width: 100px; height: 100px">Test</button>
<button style="width: 100px; height: 100px">Test</button>
</div>
</div>
This code displays the buttons as follows:
on large screen size:
bit smaller:
very small:
Edited:
The solution:
<div ng-controller="generateHTMLCtrl" id="loadhere">
<script type="text/ng-template" id="tpl">
<a style="color:{{color}}; background-color:{{backgroundcolor}};"
id="{{id}}" class="{{type}}" href="{{topage}}"
ng-controller="{{controller}}" ng-click="{{function}}">
<i class="{{icon}}"><br></i>{{name}}
</a>
</script>
</div>
what you want is something more like this:
<div class="row" ng-repeat="image in images" ng-if="$index % 4 === 0">
<div class="col col-25" ng-if="$index < images.length">
<img ng-src="{{images[$index].src}}" width="100%" />
</div>
<div class="col col-25" ng-if="$index + 1 < images.length">
<img ng-src="{{images[$index + 1].src}}" width="100%" />
</div>
<div class="col col-25" ng-if="$index + 2 < images.length">
<img ng-src="{{images[$index + 2].src}}" width="100%" />
</div>
<div class="col col-25" ng-if="$index + 3 < images.length">
<img ng-src="{{images[$index + 3].src}}" width="100%" />
</div>
</div>
This will create a maximum of 4 images per row that wrap and stack. You can also make it more or less images per by changing ng-if statement in for rows and then the amount of images in that row
When you are on every forth image, you are going to show the row class, thus creating a new row
you will pre-allocate four columns for you row, but you would first check to see if it will ever be filled to prevent an undefined exception
If the image exists at the specified index, then add it to the column
Edit!
Try this
add this css class:
.gallery {
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
}
then put this in your html:
<ion-content ng-controller="ExampleController" ng-init="loadImages()" class="gallery">
<span ng-repeat="image in images">
<img src="{{image}}" width="150px">
</span>
since ionic is built on built on top of flex box you can make a flexbox grid in ionic.

Resources