AngularJS search array of objects - javascript

I have an array of objects in my controller eg:
$scope.fields = [
{fieldName:'houseNum',fieldLabel:'House Number',disabled:false},
{fieldName:'street',fieldLabel:'Street',disabled:false},
{fieldName:'city',fieldLabel:'City',disabled:true},
{fieldName:'state',fieldLabel:'State',disabled:true},
]
In the HTML I would like to be able to get a fieldLabel where fieldName=='street'. The AJS documentation presumes that every filter case should be in the context of ng-repeat - but not so in my case as I am just trying to pluck one 'fieldLabel' from the 'fields' array based on 'fieldName'
eg: HTML
{{ fieldLabel in fields | filter : {fieldName:'street'} : true}}
How can I make something like this work - or do I need to create my own directive and pass the $scope.fields to the directive and loop through manually?

You could do:
{{ (fields | filter : {fieldName:"street"} : true)[0].fieldLabel}}
(fields | filter : {fieldName:"street"} : true) returns an array of filtered items get the first one [0] and access fieldLabel property out of that object.
angular.module('app', []).controller('ctrl', function($scope) {
$scope.fields = [{
fieldName: 'houseNum',
fieldLabel: 'House Number',
disabled: false
}, {
fieldName: 'street',
fieldLabel: 'Street',
disabled: false
}, {
fieldName: 'city',
fieldLabel: 'City',
disabled: true
}, {
fieldName: 'state',
fieldLabel: 'State',
disabled: true
}, ]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
{{ (fields | filter : {fieldName:"street"} : true)[0].fieldLabel}}
</div>
Though better option would be to set the property from the controller itself, so that the filter does not run during every digest cycle.
function getFieldByName(prop){
var field = {};
//Or just use a for loop and break once you find a match
$scope.fields.some(function(itm){
if(itm.fieldName === prop){
field = itm;
return true;
}
});
//Or you could inject $filter as well an do as below
//return $filter('filter')($scope.fields,{fieldName:"street"})[0] || {}
return field;
}
//Somewhere
$scope.streetField = getFieldByName('street');
In the view:
{{streetField.fieldLabel}}
Array.some

Related

How do I pop values of an array on deselection of chips: AngularJS

I'm implementing a filter using chips of Angular Material. When user clicks on chips, the value associated to that chip should be stored in the array. The same way, when user deselects the chip, that value should pop from the array.
I was able to store the values but selecting and deselecting are causing addition of duplicate values in the array and I'm not able to pop them out when user deselects the chip.
Here's the excerpt from my code.
HTML Code
<div layout="row">
<md-chips ng-repeat="filter in filters" readOnly="true">
<md-chip ng-style="{'background': filter.isActive ? 'green' : '' }" class="chipStyling" ng-click="setActiveFilter(filter,$index)">
{{filter.name}}
</md-chip>
</md-chips>
</div>
JS Code
angular.module('BlankApp', ['ngMaterial', 'ngMessages'])
.controller('ctrl', function($scope) {
$scope.selectedFilters = []
$scope.isActive = false;
$scope.filters = [{
name: 'Google',
code: 'g',
isActive: false
},
{
name: 'Facebook',
code: 'f',
isActive: false
},
{
name: 'Twitter',
code: 't',
isActive: false
}
]
$scope.setActiveFilter = function(filter, index) {
filter.isActive = !filter.isActive;
if (filter.isActive) {
$scope.selectedFilters.push(filter.code);
console.log('selected filter - ' + $scope.selectedFilters)
}
}
});
I created a Code Pen on this issue. Could anyone please review and correct me what I was doing wrong.
Use a splice method for remove element from array
$scope.setActiveFilter = function(filter, index) {
filter.isActive = !filter.isActive;
if (filter.isActive) {
$scope.selectedFilters.push(filter.code);
console.log('selected filter - ' + $scope.selectedFilters)
} else {
let index = $scope.selectedFilters.indexOf(filter.code);
if (index > -1) {
$scope.selectedFilters.splice(index, 1);
}
}
}

How to add dynamic class for formly-field based on controller property?

I need to add conditional Class to Form Field based on control property.
for Ex : i have in my controller
$scope.isIssueFixed = true;
and my formly object is -
$scope.formly = {
className: 'col-xs-6',
key: 'Name',
type: 'input',
templateOptions: {
label: 'Common Device Name'
}
Now how we can add a condition class to above formly field,
$scope.isIssueFixed?'ok':'No'; in formly object?
I solved the issue using Wrappers in angular formly. Here is the code which I did. May be it helps to someone.
add the bolow code to config :
formlyConfigProvider.setWrapper({
name: 'horizontalBootstrapLabel',
template: [
`<label for="{{::id}}" class="col-sm-2 control-label" >
'{{to.label}} {{to.required ? "*" : ""}}
</label>
<div class="col-sm-8" ng-class="{'bbb':model.heightlight}">
<formly-transclude></formly-transclude>
</div>`
].join(' ')
});
$scope.$watch('isIssueFixed', function() {
var classAdded = $scope.isIssueFixed ? "ok" , "No"; $scope.formly = {
className: 'col-xs-6 ' + classAdded ,
key: 'products.device[0].deviceCommonName',
type: 'input',
templateOptions: {
label: 'Common Device Name'
}
});
You can use ng-class directive of angularjs. Refere https://docs.angularjs.org/api/ng/directive/ngClass.

AngularJS access further details by matching ids

This must be simple and Angular probably has an inbuilt directive to do this but I cant think of how to do without looping through the Array.
I have a array of options i.e.
$scope.colors=[
{id:"0",label:"blue"},
{id:"1",label:"red"},
{id:"2",label:"green"}
]
And then my data object that stores the id of a color option i.e.
$scope.data={
color:"1",
otherproperty:""
}
But when I display the data to the user I want to show the label rather than the id, so is there a easy(angular) way to do this?:
{{data.color.label}}
The Angular way would be using ng-repeat & filter, your still essentially looping over the Array but all options would require some sort of loop i.e.
<div ng-repeat="color in colors | filter:{ 'id': data.color}:true">
{{ color.label }}
</div>
Setting the Filter strict comparison to 'true' as above will only select the id with an exact match
https://jsfiddle.net/sjmcpherso/wztunyr5/
The following will return the object where the id matches $scope.data.color:
var pickedColor = $scope.colors.filter(function( obj ) {
return obj.id === $scope.data.color;
});
pickedColor.label will be the label string.
Look at other way, hope it will help you.
https://jsfiddle.net/kkdvvkxk/.
We can also use $filter under controller.
Controller :
var myApp = angular.module('myApp', []);
function MyCtrl($scope, $filter) {
$scope.colors = [{
id: "0",
label: "blue"
}, {
id: "1",
label: "red"
}, {
id: "2",
label: "green"
}]
$scope.data = {
color: "1",
otherproperty: ""
}
$scope.getLabel = function(colorId) {
return $filter('filter')($scope.colors, { id: colorId }[0].label;
}
}
HTML :
{{ getLabel(data.color)}}

Angular UI-Grid filtering by strict match

I'm creating a table with Angular UI-Grid and I wanted to filter the table contents by a strict match. By default "Car" input will match with "Carol" but I want UI-Grid's filtering to only match if the input is equal to a table entry.
Try this
{
field: 'email',
filter: {
condition: uiGridConstants.filter.EXACT,
placeholder: 'your email'
}
}
Trying uiGridConstants.filter.EXACT causes fetching also CAR 1, CAR 2.
If you want to fetch "CAR" only, excluding "CAR 1" and "CAR 2", using a function would be useful:
{ field: 'name', width :'150', filter: {
condition: function(searchTerm, cellValue) {
if (searchTerm === cellValue)
return -1;
else
return 0;
}
}
}
Make a filter method. Instead of having ng-repeat="x in items|filter:filterVariable" use a filter method. In your controller code put:
var myFilter = function(x){
return x == $scope.filterVariable;
}
and the ng-repeat would look like:
ng-repeat="x in items | filter:myFilter"

Deferring Angular until Firebase data received

Right now, I am having users input data on the a sign up page, which includes having the user input their "plan type". I store this user data on Firebase.
On the following page after the user has submitted the previous input page, I take the user to an output page that uses AngularJS to show all plans filtered by the user's "plan type" (in the code, it's the customFilter). So, as soon as the page loads, I want to be able to call the user's plan type from firebase and then make it the initial filter that customFilter uses.
How do I get the Angular filter to wait until I get the "plan type' from Firebase? Any examples would be much appreciated.
I've added the code below to make this easier to answer**
<body ng-app="tipOutput" ng-controller="Tips">
<div ng-controller="MainCtrl">
// Custom filter that I want to customize based on user data
<span class="select">
<select style="width:100%" ng-model="filterItem.plan" ng-options="item.name for item in filterOptions.plans"></select>
</span>
// Table using ng-repeat and above filter
<table>
<tbody>
<tr ng-repeat="tip in tips | filter:customFilter">
<td style="vertical-align:top"><span><strong>{{tip.planName}}</strong></span><span ng-show="tip.planDetail">Plan Detail: {{tip.planDetail}}</span></td>
</tr>
</tbody>
</table>
</div>
</body>
Angular app code here
angular.module('tipOutput', ['firebase', 'filters'])
.controller('Tips', ['$scope', 'angularFire',
function ($scope, angularFire) {
var ref = new Firebase('https://sitename.firebaseio.com/tips');
angularFire(ref, $scope, "tips");
}])
.controller('MainCtrl', function($scope) {
//Contains the filter options
$scope.filterOptions = {
plans: [
{id : 2, name : 'All Plans', type: 'all' },
{id : 3, name : 'Plan Type 1', type: 'plan-type-1' },
{id : 4, name : 'Plan Type 2', type: 'plan-type-2' },
{id : 5, name : 'Plan Type 3', type: 'plan-type-3' },
{id : 6, name : 'Plan Type 4', type: 'plan-type-4' },
{id : 7, name : 'Plan Type 5', type: 'plan-type-5' },
{id : 8, name : 'Plan Type 6', type: 'plan-type-6' }
]
};
// Here's where the initial value of the filter is set. Currently, it's not dynamic, but I
// want it to be based off a variable that comes in asynchronously (i.e. likely after this
// code would otherwise run)
$scope.filterItem = {
plan: $scope.filterOptions.plans[0]
}
//Custom filter - filter based on the plan type selected
$scope.customFilter = function (tip) {
if (tip.servicesReceived === $scope.filterItem.plan.type) {
return true;
} else if ($scope.filterItem.plan.type === 'all') {
return true;
} else {
return false;
}
};
})
I tried to simulate your call to your firebase.
DEMO: http://plnkr.co/edit/VDmTCmR82IyaKnfaT1CP?p=preview
html
<body ng-controller="MainCtrl">
<p>Hello {{name}}!</p>
<div>
<span class="select">
<select ng-model="filterItem.plan" ng-options="item.name for item in filterOptions.plans"></select>
</span>
<table border="1">
<tbody>
<tr ng-repeat="tip in (filtered = (tips | filter:customFilter))">
<td>
<span><strong>{{tip.planName}}</strong></span>
<span>Plan Detail: {{tip.planDetail}}</span>
</td>
</tr>
<tr ng-show="filtered.length==0">
<td>None</td>
</tr>
</tbody>
</table>
</div>
</body>
I keep the filtered list to be able to display a message if there is no items.
js
var app = angular.module('plunker', ['firebase']);
app.controller('MainCtrl', function($scope, $timeout, angularFire) {
$scope.name = 'World';
$scope.tips = [];
/*
// since we dont have access to your firebase, i used a $timeout
var ref = new Firebase('https://sitename.firebaseio.com/tips');
// we wait for the callback of angularFire
angularFire(ref, $scope, "tips").then(function(response) {
var index = 1; // find the good index in filterOptions
$scope.filterItem.plan = $scope.filterOptions.plans[index];
});*/
// simulate the response
$timeout(function() {
$scope.tips = [
{planName: '213', planDetail:'534',servicesReceived:'plan-type-1'},
{planName: '123', planDetail:'345',servicesReceived:'plan-type-2'},
{planName: '321', planDetail:'643'} // this one has no serviceReceived
];
// set it to the response receive from the server
var response = 1;
$scope.filterItem.plan = $scope.filterOptions.plans[response];
}, 1000);
$scope.filterOptions = {
plans: [
{id : 2, name : 'All Plans', type: 'all' },
{id : 3, name : 'Plan Type 1', type: 'plan-type-1' },
{id : 4, name : 'Plan Type 2', type: 'plan-type-2' },
{id : 5, name : 'Plan Type 3', type: 'plan-type-3' },
{id : 6, name : 'Plan Type 4', type: 'plan-type-4' },
{id : 7, name : 'Plan Type 5', type: 'plan-type-5' },
{id : 8, name : 'Plan Type 6', type: 'plan-type-6' }
]
};
// default value
$scope.filterItem = {
plan: $scope.filterOptions.plans[0] // Do something with response
}
$scope.customFilter = function (tip) {
return (tip.servicesReceived || 'all') === $scope.filterItem.plan.type;
};
});
Resolve the fireBase Data on the route. This will prohibit the controller from loading before the data is present. Then just inject the data into the controller and continue forward with your normal process.
I'm not going to write it using your variables, but an exmaple of such a config file would look like:
'use strict';
angular.module('someModule.dashboard')
.config(function ($stateProvider){
$stateProvider
.state('dashboard', {
url: '/dashboard',
templateUrl: '/app/dashboard/html/dashboard.html',
controller: 'dashBoardCtrl',
resolve: {
currentAuth: function(fireBaseAuth){
return fireBaseAuth.auth().$requireAuth();
},
currentUser: function($fireBaseUser, Session){
return $fireBaseUser.user(Session.id).$asObject();
},
userList: function($fireBaseUser){
return $fireBaseUser.userList().$asArray();
}
}
});
});
Then Your controller would look something like this:
'use strict';
angular.module('someModule.dashboard')
.controller('dashBoardCtrl', function($scope, currentUser, userList){
$scope.userList = userList;
});

Categories