I want to create specific custom filter which will filter object by "colors" I have bigger object but for this case I created small one only to show you what is the issue so I have json like this:
[
{
"nazwa": "koszule",
"colors": [
"white"
],
"rozmiary": [],
"url": "/pl/p/koszule/3693",
"rodzaj": 2,
"img": "/images/nophoto_300x300.jpg",
"muszka": null,
"alt": "koszule"
},
{
"nazwa": "koszule",
"colors": [
"blue"
],
"rozmiary": [],
"url": "/pl/p/koszule/3693",
"rodzaj": 2,
"img": "/images/nophoto_300x300.jpg",
"muszka": null,
"alt": "koszule"
},
{
"nazwa": "koszule",
"colors": [
"white",
"blue"
],
"rozmiary": [],
"url": "/pl/p/koszule/3693",
"rodzaj": 2,
"img": "/images/nophoto_300x300.jpg",
"muszka": null,
"alt": "koszule"
}
]
I also have multiple select in my view
<md-input-container class="md-block" flex-gt-sm>
<md-select ng-change="checkColors()" ng-model="kolorEnd" multiple>
<md-optgroup label="<?php echo $this->translate('kolory'); ?>">
<md-option ng-value="unikalneKoloryWidok" ng-repeat="unikalneKoloryWidok in unikalneKolory | orderBy : expression">{{unikalneKoloryWidok}} </md-option>
</md-optgroup>
</md-select>
</md-input-container>
and in controller is:
$scope.dataParsed = angular.fromJson(prdData);
angular.forEach($scope.dataParsed , function(item , i) {
angular.forEach(item.kolory , function(item , i) {
wszystkieKolory.push(item);
});
});
$scope.unikalneKolory = $.unique(wszystkieKolory);
$scope.checkColors = function(){
$scope.$watch('kolorEnd' , function(oldv,newv) {
$scope.kolory = oldv.toString();
});
};
frost.filter('colorsFlt' , function(){
return function(data,inpArray) {
var output = [];
if (angular.isArray(inpArray)) {
}
}
What I want to achieve is - if someone select only 'white' option show only products which has 'white' color, if customer select 'white' and 'blue' it supposed to show products which has only white and only blue but also products which has ['white','blue'].
I am in a trap:) And don't know how to write my filter to achieve this. Please help;)
So I achieved what I wanted by trying different things:) here is the code in future use:
controller
frost.filter('megaFlt' , function(){
return function(data,firstarg , secarg , filtertype) {
var output = [];
if (angular.isString(firstarg) || angular.isString(secarg)) {
angular.forEach(data,function(el,j) {
$.map(el[filtertype],function(test,i){
if(test == firstarg || test == secarg ) {
return output.push(data[j]);
}
});
});
return output;
}
else {
return data;
}
}
});
view
<md-input-container class="md-block" flex-gt-sm>
<md-select ng-change="checkColors()" ng-model="kolorEnd" multiple>
<md-optgroup label="<?php echo $this->translate('kolory'); ?>">
<md-option ng-value="unikalneKoloryWidok" ng-repeat="unikalneKoloryWidok in unikalneKolory | orderBy : expression">{{unikalneKoloryWidok}} </md-option>
</md-optgroup>
</md-select>
</md-input-container>
and put filter in ng-repeat element
| megaFlt:kolorEnd[0]:kolorEnd[1]:'kolory'
Related
I a getting error
TypeError: Cannot read property 'some' of undefined
at
MdChipsCtrl.appendChip (angular-material.js:27485)
at MdChipsCtrl.<anonymous> (angular-material.js:27791)
at angular.js:1256
The looping is undefined and it has to create afinal array of all the selected values. Below is the code that takes only one chip per input field.
html
<div layout="column" style="background-color: #fff" layout-padding>
<h1>MISTAKE TTYPES</h1>
<div layout="column" ng-cloak>
<div class="md-padding" layout="column">
<form name="fruitForm">
<div ng-repeat="items in [1,2]">
<md-chips ng-model="vm.selectedMistakes[$index]" md-autocomplete-snap
md-on-remove = "vm.removeChip($index)"
name="fruitName[$index]" >
<md-autocomplete
md-selected-item="vm.selectedItem[$parent.$index]"
md-no-cache="vm.noCache"
md-max-chips="1"
md-search-text="vm.searchText"
md-items="item in vm.mistakes"
md-item-text="item.name"
md-selected-item-change="vm.searchTextChange($index)"
placeholder={{vm.placeholder}}
name="fruitNameAuto[$parent.$index]">
<span md-highlight-text="vm.searchText">{{item.name}}</span>
</md-autocomplete>
<md-chip-template>
<span>
<strong>{{$chip.name}}</strong>
</span>
</md-chip-template>
</md-chips>
</div>
</form>
</div>
</div>
</div>
Controller
(function () {
'use strict';
angular
.module('app')
.controller('chipsCtrl', chipsCtrl);
/* #ngInject */
function chipsCtrl($q,$timeout) {
var vm = this;
vm.selectedItem = null;
vm.searchText = null;
vm.mistakes = loadMistakes();
vm.selectedMistakes = [[],[]];
vm.transformChip = transformChip;
vm.searchTextChange = searchTextChange;
vm.removeChip = removeChip;
/**
* Return the proper object when the append is called.
*/
function transformChip(chip) {
console.log(chip);
// If it is an object, it's already a known chip
if (angular.isObject(chip)) {
return chip;
}
// Otherwise, create a new one
return { name: chip, id: 1 }
}
vm.placeholder = "Select Mistake Type";
function searchTextChange(index) {
//console.log(vm.selectedMistakes);
vm.searchText = null;
if(vm.selectedMistakes[index]){
vm.placeholder = (vm.selectedMistakes[index].length > 0) ? "Just 1 allowed" : "Select Mistake Type";
}
}
function removeChip(index){
vm.placeholder = (vm.selectedMistakes[index].length > 0) ? "Just 1 allowed" : "Select Mistake Type";
}
function loadMistakes() {
return [
{
'name': 'Simple',
'id': 1
},
{
'name': 'Conceptual',
'id': 2
},
{
'name': 'Silly',
'id': 3
},
{
'name': 'Visual',
'id': 4
},
{
'name': 'dilemma',
'id': 5
}
];
}
}
})();
EXPECTED OUTPUT :
vm.selectedMistakes = [
[
{
"name": "Conceptual",
"id": 2
}
],
[
{
"name": "Simple",
"id": 1
}
]
]
I am getting smae value triggered to both the inputs
I'm using md-select and need to trigger certain code when the value changes (building a Country/State selector). I have it working fine when I change the value through the control but I also need to have the controls reflect the values properly when the model is changed from code. I'm using ng-change to trigger the change code (need ng-change as user can change the value from the keyboard without clicking on it). The problem is that when the value is changed from the code, the event isn't fired. To complicate things a bit more, the md-selects live in a directive to allow me to use the setup in several places.
Here's my directive template:
<md-input-container class="md-block">
<label>Country</label>
<md-select name="country" ng-model="countryState.countryModel" ng-change="countryState.onCountrySelected()">
<md-option ng-repeat="country in countryState.countries" ng-value="country.itemId">
{{ country.name | translate }}
</md-option>
</md-select>
</md-input-container>
<md-input-container class="md-block">
<label>State</label>
<md-select name="state" ng-model="countryState.stateModel" ng-disabled="countryState.countryModel == null">
<md-option ng-repeat="state in countryState.states" ng-value="state.itemId">
{{ state.name | translate }}
</md-option>
</md-select>
</md-input-container>
Here's the directive code:
angular.module('myapp.shared')
.directive('countryStateInput', [function () {
return {
restrict: 'E',
templateUrl: 'app/shared/inputs/countryState/country-state-input.directive.html',
transclude: false,
scope: {
coordsForm: '=',
countryModel: '=',
stateModel: '='
},
bindToController: true,
controllerAs: 'countryState',
controller: ['$scope', '$document', 'OptionService', function($scope, $document, OptionService) {
var ctrl = this;
// Properties
ctrl.countries = null;
ctrl.states = [];
ctrl.selectedCountryIndex = null;
ctrl.onCountrySelected = function() {
// Get the index of the country
for (var i = 0; i < ctrl.countries.length; i++) {
if (ctrl.countryModel === ctrl.countries[i].itemId) {
// If a different country was chosen, clear the selected state
if (i !== ctrl.selectedCountryIndex) {
ctrl.stateModel = null;
angular.copy(ctrl.countries[i].states, ctrl.states);
};
// Save the index of the selected country
ctrl.selectedCountryIndex = i;
return;
}
}
};
// Initialization
var initialize = function () {
OptionService.getCountries().then(
function (result) {
ctrl.countries = result;
});
};
(function () {
$document.ready(function () {
initialize();
})
})();
}]
}
}]);
Here's a usage example:
<country-state-input country-model="app.location.countryId" state-model="app.location.stateId" input-form="locationsForm"></country-state-input>
And OptionService.getCountries() returns something like this (states lists are shortened):
[
{
"itemId": 1,
"name": "CA",
"states": [
{
"itemId": 1,
"name": "CA_ON",
"abbreviation": "ON"
},
{
"itemId": 2,
"name": "CA_QC",
"abbreviation": "QC"
}
]
},
{
"itemId": 2,
"name": "US",
"states": [
{
"itemId": 14,
"name": "US_AL",
"abbreviation": "AL"
},
{
"itemId": 15,
"name": "US_AK",
"abbreviation": "AK"
}
]
}
]
Basically, I'm trying to figure out if there's a way to trigger onCountrySelected that will cover all 3 use cases.
You could use $scope.$watch
$scope.$watch(
function valueGetter(){
return smth;
},
function onChange(newSmth, oldSmth){
}
)
I'm trying to applay a filter in my ng-repeat based on a nested array. The object that is used for the ng-repeat:
Updated
master_array:
{
"0": {
"Employee_Id": "hni",
"comptencies": [
{
"Title": "Bunker Knowledge",
"Level": 1
},
{
"Title": "Bunker Knowledge",
"Level": 3
},
{
"Title": "IT Compliance",
"Level": 2
},
{
"Title": "Bunker Knowledge",
"Level": 5
}
],
}
}
JS:
$scope.myFilter = {
competencyTitle : ""
}
HTML:
<label>Competencies
<select ng-model="myFilter.competencyTitle" ng-options="item.Title for item in competencies_list"></select>
</label>
<tr ng-repeat="item in master_array | filter: { competencies: [{ Competency.Title: myFilter.competencyTitle }] }">
The above doesn't work.
Case
I have a list of employees and each employee has an id and array of competencies attached. Each item in this array has a comptency array attached, which holds the title an id of the competency. What I want is to be able to filter out employees with specific competencies.
Any suggestions?
I found a solution. You probably have to adapt it to your specific code:
The main idea is this: filter: { $: {Title: myFilter.competencyTitle.Title} }
The $ selects any element whose child is Title.
html
<label>Competencies {{myFilter.competencyTitle.Title}}
<select ng-model="myFilter.competencyTitle" ng-options="item.Title for item in competencies_list"></select>
</label>
<p ng-repeat="item in master_array | filter: { $: {Title: myFilter.competencyTitle.Title} }">{{item.employee_id}} {{item.competencies}} </p>
js - this is the model is used, I'm not sure if this reflects your actual model.
$scope.competencies_list = [{Title : "Math"},{Title : "English"},{Title : "Spanish"}];
$scope.master_array =
[
{
employee_id: "hni",
competencies:
[
{Title : "Math", "Level": 1},
{Title : "English", "Level": 2}
]
},
{
employee_id: "xyz",
competencies:
[
{Title : "Spanish", "Level": 3},
{Title : "English", "Level": 5}
]
}
];
$scope.myFilter = {
competencyTitle : ""
};
Products have 4 different category. I want to show them into 3 section. How to do this with angularjs? I want to repeat ng-repeat based on product category.
Please check my plnkr: http://plnkr.co/edit/XdB2tv03RvYLrUsXFRbw?p=preview
var product = [
{
"name": "Item 1",
"dimension": {
"height": "4 in",
"width": "3 in"
},
"category": "A"
}, {
"name": "Item 2",
"dimension": {
"height": "2 in",
"width": "6 in"
},
"category": "B"
}, {
"name": "Item 3",
"dimension": {
"height": "2 in",
"width": "3 in"
},
"category": "C"
}, {
"name": "Item 4",
"dimension": {
"height": "5 in",
"width": "2 in"
},
"category": "D"
}
];
You can use a filter :
ng-repeat="item in output.products | filter:{ category: 'A'}"
Edit : looks like everybody googled the same thig and found the same other StackOverflow answer ^^ #OP you should learn how to Google, btw !
Edit 2 : Reread the question, you need a custom filter :
app.filter('category', function() {
return function(items, categories) {
if (!items || items.length === 0) {
return [];
}
return items.filter(function(item) {
return categories.indexOf(item.category) > -1;
});
};
});
Use it like follows :
ng-repeat="item in output.products | category:['A', 'B']"
Edit 3 : be aware, though, that this can be pretty expensive in terms of performances for huge arrays. If you're dealing with such arrays, I suggest pre-filtering the data into several subarrays.
You can use angular.filter module.
You will have to define your own map function in the controller:
$scope.group = function(elem){
if(elem.category == 'C' || elem.category=='D'){
elem.category = 'C OR D' ;
return elem;
}
else return elem;
}
then in the html
<ul ng-repeat="(key, value) in products | map: group | groupBy: 'category'">
Group name: {{ key }}
<li ng-repeat="product in value">
player: {{ product.name }}
</li>
</ul>
note that you are loosing the information on the category of the element if it is C Or D, thing that won't happen if you use LoremIpsum's answer, but with this solution you will be able to create whatever groups you want.
here is a js fiddle with an example.
for example <div class="" ng-repeat="item in output.products | filter: {category:'A'}"> Whould only repeat items with Category A. You could also filter with a self defined function or other criteria.
You can use ng.if for this to.
Check here http://plnkr.co/edit/SKfUKTtKhUnZqec3ABSt?p=preview
<div class="" ng-repeat="item in output.products" ng-if='item.category =="A"'>
Is there a way to perform nested loops in an AngularJS view without creating hidden dummy elements?
Something like this:
<ul>
<li ng-repeat="gem in activeHero.gems"
ng-repeat="(key, value) in gem.attributes"
ng-repeat="attr in value">
{{attr.text}}
</li>
</ul>
or this
<ul>
<li ng-repeat-start="gem in activeHero.gems"
ng-repeat-start="(key, value) in gem.attributes"
ng-repeat="attr in value">
{{attr.text}}
</li ng-repeat-end
ng-repeat-end>
</ul>
Neither of these is possible AFAIK.
I basically want my HTML to have a different structure than the JSON it's based on.
How could I achive this? Is there a way to create loops inside a view without an HTML element?
The examples above would loop over a JSON structure like this:
JSON (stripped out a lot for clarity)
"activeHero" = {
"gems" : [ {
"attributes" : {
"primary" : [ {
"text" : "+220 Intelligence"
} ],
"secondary" : [ ],
"passive" : [ ]
}
}, {
"attributes" : {
"primary" : [ {
"text" : "+220 Intelligence"
} ],
"secondary" : [ ],
"passive" : [ ]
}
}, {
"attributes" : {
"primary" : [ {
"text" : "+160 Intelligence"
} ],
"secondary" : [ ],
"passive" : [ ]
}
} ]
}
(This is an actual JSON response from the Blizzard API for the video game "Diablo 3")
Try format your json before render;
$scope.formattedData = [];
angular.forEach(activeHero.gems, function(value, key){
var item = {
//set filed you want
}
angular.forEach(value.atrtibutes, function(value2, key2){
item['propyouwant'] = value2[propyouwant]
angular.forEach(value2.primary, function(value3, key3){
item['propyouwant'] = value3[propyouwant]
$scope.formattedData.push(angular.extend({}, item));
})
})
})
//now you can render your data without somersould
EDIT
For increasing performance and avoid to use angular extend;
$scope.formattedData = [];
angular.forEach(activeHero.gems, function(value, key){
angular.forEach(value.atrtibutes, function(value2, key2){
angular.forEach(value2.primary, function(value3, key3){
//start build your item here
var item = {
prop1: value['prop'],
prop2: value2['prop']
}
//not required extend item;
$scope.formattedData.push(item);
})
})
})