AngluarJS: using filter in controller - angularjs

I have this controller:
angular.module('myApp', [])
.controller('testCtrl', ['$scope', '$filter',
function($scope, $filter) {
$scope.users = [{
name: "Hanna",
gender: "female"
}, {
name: "Martin",
gender: "male"
}, {
name: "Kim",
gender: "transgender"
}];
$scope.traditionalUsers = $filter('filter')($scope.users,femaleOrMale());
function femaleOrMale(user) {
return ['female','male'].indexOf(user.gender);
}
}
]);
I want to filter users that has a property that matches an array. This does not work. See plunk. How can I correctly call the filter-filter?

Remove the ()
You're calling the femaleOrMale function without any parameters when you write femaleOrMale() in
$scope.traditionalUsers = $filter('filter')($scope.users, femaleOrMale());
What you write to pass the function itself to the filter is
$scope.traditionalUsers = $filter('filter')($scope.users, femaleOrMale);
This will make the page not throw an error anymore, however it wont display male and female as traditional users, which i suspect is what you want. You need to return a boolean from the femaleOrMale filter, and indexOf returns the index of the match, or -1 if there is no match, so compare for -1.
return ['female','male'].indexOf(user.gender) != -1;
angular.module('myApp', [])
.controller('testCtrl', ['$scope', '$filter',
function($scope, $filter) {
$scope.users = [{
name: "Hanna",
gender: "female"
}, {
name: "Martin",
gender: "male"
}, {
name: "Kim",
gender: "transgender"
}];
$scope.traditionalUsers = $filter('filter')($scope.users, femaleOrMale);
function femaleOrMale(user) {
return ['female','male'].indexOf(user.gender) != -1;
}
}
]);
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body>
<div ng-app='myApp'>
<div ng-controller='testCtrl'>
<h3>Male and female users:</h3>
{{traditionalUsers}}
</div>
</div>
</body>
</html>

Related

How to update in ionic

Im trying to update my already existing entries using angularjs and ionic.I have two views, in the first view I have listed the car name and its model name. When the car name is selected, it is directed to second view where the information regarding the selected car name and its models are listed so that they are edited and updated.I have declared $rootScope.selectItem=key; which help to show what is the selected car name. I face problem in update so, I need help in updating the information by replacing the new information with old information.
view 1:
<ion-list>
<ion-item ng-model="carBrand" ng-repeat="name in carSelect">
<button ng-click="selectItem(name)">{{name.name}}</button>
<div class="item" ng-repeat="type in name.types">{{type}}</div>
</ion-item>
</ion-list>
view 2:
<input type="text" ng-model="newName"><br> Select Type:{{selectItem}}</div>
<ion-checkbox ng-repeat="field in fields" ng-model="field.checked" ng-checked="field.checked">
{{field.name}}
</ion-checkbox>
<button ng-click="remove()">Delete</button>
<button ng-click="Update()">Update</button></div>
Controller:
carService.controller('carBrand', ['$scope', 'carRepository', '$rootScope', '$state', '$stateParams', function ($scope, carRepository, $rootScope, $state, $stateParams) {
$rootScope.carSelect = carRepository.data;
$scope.newCarList = [];
$scope.selectItem = function (key) {
$rootScope.selectItem=key;
$state.go('app.carModel');
}
carService.controller('carAdd', ['$scope', '$rootScope', '$state', function ($scope, $rootScope, $state) {
$scope.newName = "";
$scope.fields = [{ id: 1, name: 'Regular' },
{ id: 2, name: 'SUV' },
{ id: 3, name: 'Oversize' },
{ id: 4, name: 'Truck' },
{ id: 5, name: 'Motorcycle' }];
$scope.sample = [];
$scope.Update = function () {
var carType = [];
....}
If I were you, I would change some things to make it more application-like.
First of all, change your state routing:
$stateProvider.state("app.carModel", {
// ..
url: "edit/:id"
}
Then in your selectedItem function:
$scope.selectItem = function (car) {
// assuming your cars have an id property
// you can ofcourse also use something else
$state.go('app.carModel', { id: car.id });
}
Then in your edit/add controller:
carService.controller('carAdd', ['$scope', '$stateParams', 'carRepository', function ($scope, $stateParams, carRepository) {
var carId = $stateParams.id;
// make a copy, so it only gets changed in the repository when the user
// presses 'Update'
$scope.car = angular.copy(carRepository.get(carId));
$scope.fields = [{ id: 1, name: 'Regular' },
{ id: 2, name: 'SUV' },
{ id: 3, name: 'Oversize' },
{ id: 4, name: 'Truck' },
{ id: 5, name: 'Motorcycle' }
];
$scope.sample = [];
$scope.Update = function () {
// ..
// in the save function replace the existing with the edited
carRepository.save($scope.car);
}
}

Catching ng-repeat duplicate error

I have this template:
<li ng-repeat="item in results.items track by item.id"><ul result-list-line></ul></li>
Sometimes I get Duplicates in a repeater are not allowed. Basically a back-end problem, but I need to handle it in the FE.
Now, I know it's been discussed before: I can loop over the data and catch duplicate myself or I can bypass it by using track by $index. I don't want to do either – I want to catch the Angular error and handle it (display an error message, basically). How do I do that?
Here's my version to Stepan Kasyanenko's answer below:
.factory('$exceptionHandler', [ '$injector', function ( $injector ) {
return function (exception, cause) {
// Preventing circular reference when using $rootScope
var $rootScope = $injector.get('$rootScope');
var msg = exception.message;
// Still have the usual console error - extend instead of replace
var $log = $injector.get('$log');
$log.error.apply($log, arguments);
//catching ngRepeat duplicates
if ( msg.search("ngRepeat:dupes") > -1 ) {
msg = "Duplicate entries were sent from the server"
}
// Not always you get a cause string, but if so you might want to add it to the message
if ( cause ) {
msg += ". Cause: "+cause;
}
// No matter what I did, I couldn't inject any factory that uses $rootScope, so I used custom event instead
$rootScope.$emit("angularError", msg);
};
}])
You can use $exceptionHandler.
Live example on jsfiddle.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.countries = [{
countryName: 'United States',
countryCode: 1
}, {
countryName: 'Canada',
countryCode: 2
}, {
countryName: 'Bahamas',
countryCode: 3
}, {
countryName: 'Chile',
countryCode: 4
}, {
countryName: 'Chile',
countryCode: 4
}];
})
.factory('$exceptionHandler', function() {
return function(exception, cause) {
alert(exception)
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<label>Country:</label>
<div ng-repeat="country in countries track by country.countryCode">
{{country.countryName}}
</div>
</div>
</div>
UPDATED
$exceptionHandler handle also custom error.
angular.module('ExampleApp', [])
.controller('ExampleController', function($scope) {
$scope.countries = [{
countryName: 'United States',
countryCode: 1
}, {
countryName: 'Canada',
countryCode: 2
}, {
countryName: 'Bahamas',
countryCode: 3
}, {
countryName: 'Chile',
countryCode: 4
}, ];
$scope.raiseError = function() {
throw "my raiseError";
}
$scope.addBadElement = function() {
$scope.countries.push({
countryName: 'Chile',
countryCode: 4
});
}
})
.factory('$exceptionHandler', function() {
return function(exception, cause) {
alert(exception);
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="ExampleApp">
<div ng-controller="ExampleController">
<label>Country:</label>
<button ng-click="raiseError()">
raise Error
</button>
<button ng-click="addBadElement()">
Add Bad Country
</button>
<div ng-repeat="country in countries track by country.countryCode">
{{country.countryName}}
</div>
</div>
</div>

AngularJS NG-Repeat Seems to Not Work on Array with Single Object

I have found many posts about how ng-repeat does not play well with objects, and expects the data to be an array, but my data is an array, it just happens to have a single object(list2). I get list1 fine, and everything works perfect. According to everything that I have found, list2 should work. Anyone know why it doesn't?
Data coming from my factory:
(function(){
var Factory = function(){
var model = {
list1: [
{
id: "1_1",
type: "header",
headerText: "1_1 Header",
secondaryHeaderText: "",
paragraphText: "1_1 Paragraph",
image: ""
},
{
id: "1_2",
type: "header",
headerText: "Header 1_2",
secondaryHeaderText: "",
paragraphText: "1_2 Paragraph",
image: ""
},
{
id: "1_3",
type: "header",
headerText: "1_3 Header1",
secondaryHeaderText: "1_3 Header2",
paragraphText: "",
image: ""
}
],
list2: [
{
id: "2_1",
type: "link",
headerText: "2_1 Header",
paragraphText: "2_1 Paragraph",
linkText: "2_1 Link Text",
image: ""
}
]
};
var factory = {};
factory.getList1 = function(){
return model.list1;
};
factory.getList2 = function(){
return model.list2;
};
return factory;
};
angular.module('designApp').factory('Factory', Factory);
}());
HMTL
<div>
<!--works perfectly fine -->
<div ng-repeat="item in list1" ng-include="'app/partial/list1.html'"></div>
</div>
<div>
<div ng-repeat="item in list2" ng-include="'app/partial/list2.html'"></div>
</div>
Controller
(function(){
var Controller = function($scope, Factory){
$scope.list1 = [];
$scope.list2 = [];
function init(){
$scope.list1 = Factory.getList1();
$scope.list2 = Factory.getList2();
}
init();
};
Controller.$inject = ['$scope', 'Factory'];
angular.module('designApp')
.controller('Controller', Controller);
}());
This is all that is in list2.html. Does not render any of the model data but renders the html tags, and throws no errors.
<h2>{{list2.headerText}}</h2>
<p>{{list2.paragraphText}}</p>
Thanks in advance for any help!
You have to replace
<h2>{{list2.headerText}}</h2>
<p>{{list2.paragraphText}}</p>
by
<h2>{{item.headerText}}</h2>
<p>{{item.paragraphText}}</p>
working plunkr:
https://plnkr.co/edit/FC5KPpOl7gsmfva63veq?p=preview

How to chain AngularJS filters in controller

I have few filters in view
<tr ng-repeat="x in list | filter:search| offset:currentPage*pageSize| limitTo:pageSize ">
In my project to achieve good result, i have to make this filtering in controller not in view
i know the basic syntax $filter('filter')('x','x') but i don't know how to make chain of filters in controller, so everything will work as in my example from template.
I found some solution, now just with one filter, but should work with many ;)
$scope.data = data; //my geojson from factory//
$scope.geojson = {}; //i have to make empty object to extend it scope later with data, it is solution i found for leaflet //
$scope.geojson.data = [];
$scope.FilteredGeojson = function() {
var result = $scope.data;
if ($scope.data) {
result = $filter('limitTo')(result,10);
$scope.geojson.data = result;
console.log('success');
}
return result;
};
and i use this function in ng-repeat works fine, but i have to check it with few filters.
You can just re-filter what you get returned from your first filter. So on and so forth.
var filtered;
filtered = $filter('filter')($scope.list, {name: $scope.filterParams.nameSearch});
filtered = $filter('orderBy')(filtered, $scope.filterParams.order);
Below plunkr demonstrates the above.
http://plnkr.co/edit/Ej1O36aOrHoNdTMxH2vH?p=preview
In addition to explicitly applying filters to the result of the previous one you could also build an object that will chain multiple filters together.
Controller
angular.module('Demo', []);
angular.module('Demo')
.controller('DemoCtrl', function($scope, $filter) {
$scope.order = 'calories';
$scope.filteredFruits = $scope.fruits = [{ name: 'Apple', calories: 80 }, { name: 'Grapes', calories: 100 }, { name: 'Lemon', calories: 25 }, { name: 'Lime', calories: 20 }, { name: 'Peach', calories: 85 }, { name: 'Orange', calories: 75 }, { name: 'Strawberry', calories: 65 }];
$scope.filterFruits = function(){
var chain = new filterChain($scope.fruits);
$scope.filteredFruits = chain
.applyFilter('filter', [{ name: $scope.filter }])
.applyFilter('orderBy', [ $scope.order ])
.value;
};
function filterChain(value) {
this.value = value;
}
filterChain.prototype.applyFilter = function(filterName, args) {
args.unshift(this.value);
this.value = $filter(filterName).apply(undefined, args)
return this;
};
});
View
<!doctype html>
<html ng-app="Demo">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script src="script.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="DemoCtrl">
<input type="text" ng-model="filter" ng-change="filterFruits()" placeholder="Filter Fruits" />
<select ng-model="order">
<option value="name">name</option>
<option value="calories">calories</option>
</select>
<div ng-repeat="fruit in filteredFruits">
<strong>Name:</strong> {{fruit.name}}
<strong>Calories:</strong> {{fruit.calories}}
</div>
</div>
</body>
</html>
This is a typical case for FP libraries like lodash or Ramda. Make sure your common data is applied as last arg to each filter. (in this case columns)
$scope.columnDefs = _.compose(
$filter('filter3'),
$filter('filter2'),
$filter('filter1')
)($scope.columns)
or with extra args
$scope.columnDefs = _.compose(
$filter('filter3').bind(null, optionalArg1, optionalArg2),
$filter('filter2').bind(null, optionalArg1),
$filter('filter1')
)($scope.columns)

I can not get the select working correctly in angularjs

I tried to do as this article recommends to get select-options working in AngularJS.
http://gurustop.net/blog/2014/01/28/common-problems-and-solutions-when-using-select-elements-with-angular-js-ng-options-initial-selection/
However I have got it messed up some how. Here is a fiddlerjs of the code
http://jsfiddle.net/8faa5/
Here is the HTML
<!DOCTYPE html>
<html class="no-js" data-ng-app="TestModule">
<head>
<title></title>
</head>
<body data-ng-controller="TestController">
<h3>Test Select</h3>
Current Value: {{ ourData.CurrentSelected}} <br>
<select ng-init="ourData._currVal = {Value: ourData.CurrentSelected}"
ng-change="ourData.CurrentSelected = ourData._currVal.Value"
ng-model="ourData._currVal"
ng-options="oneItem.Value as oneItem.Disp
for oneItem in ourData.StuffForDropDown track by oneItem.Value"></select>
<!-- Get Javascript -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"></script>
<script src="js/data.js"></script>
</body>
</html>
Here is js/data.js
(function() {
"use strict";
var smallData = {
StuffForDropDown: [
{
Disp: "01-Prospect",
Value: 5
},
{
Disp: "02-Constituet Issue",
Value: 10
}
],
CurrentSelected: "10"
};
var myModule = angular.module("TestModule", ['ui.mask']);
myModule.controller("TestController", ["$scope",
function ($scope){
$scope.ourData = smallData;
}
]);
})();
First of all, your jsfiddle is messed up. You have defined angularjs twice, once in the jsfiddle options and the second time in the code. Also you overcomplicated your code. I made a simple rewrite of your code that is working in this jsfiddle.
<div data-ng-app="TestModule">
<div data-ng-controller="TestController">
<h3>Test Select</h3>
Current Value: {{ ourData._currval}}
<br>
<select ng-init="ourData._currVal = {Value: ourData.CurrentSelected}"
ng-model="ourData._currval" ng-options="oneItem.Value as oneItem.Disp
for oneItem in ourData.StuffForDropDown"></select>
</div>
</div>
(function () {
"use strict";
var smallData = {
StuffForDropDown: [{
Disp: "01-Prospect",
Value: 5
}, {
Disp: "02-Constituet Issue",
Value: 10
}],
CurrentSelected: "10"
};
var myModule = angular.module("TestModule", []);
myModule.controller("TestController", ["$scope",
function ($scope) {
$scope.ourData = smallData;
}]);
})();
**Edit:
OK, I have revised my code according to your new request int the comment. The code goes as follows (new plunker)
<div data-ng-app="TestModule">
<div data-ng-controller="TestController">
<h3>Test Select</h3>
Current Value: {{ currentItem.Value}}
<br>
<select ng-model="currentItem" ng-options="u as u.Disp for u in items track by u.Value"></select>
</div>
</div>
(function () {
"use strict";
var myModule = angular.module("TestModule", []);
var ctrl = function ($scope) {
$scope.items = [{
Disp: "01-Prospect",
Value: 5
}, {
Disp: "02-Constituet Issue",
Value: 10
}];
$scope.currentItem = $scope.items[1];
};
myModule.controller("TestController", ctrl)
})();

Resources