AngularJS determine filter in controller - angularjs

How would I go about setting the filter property on an ng-repeat dynamically?
Here is my template...
<div class="list-group">
<div ng-repeat="article in articles | activeFilter">
<a href="#" class="list-group-item">
<h3 class="list-group-item-heading">{{ article.title }}</h3>
<h4 class="list-group-item-text">{{ article.author }}</h4>
<p class="list-group-item-text">"{{ article.blurb }}"</p>
</a>
</div>
</div>
Where "activeFilter" is a property I want to set via the controller...
...
$scope.activeFilter = 'someFilterType'
...
And the filter looks like this...
.filter('someFilterType', function () {
return function (items) {
var rv = [];
for (var p in items) {
if (items[p].myFilterProp === false)
rv.push(items[p]);
}
return rv;
}
})
I would think I could dynamically change the ng-repeat's filter in this way, but it doesn't seem to be working and I'm not sure why.

Try something like this:
HTML
ng-repeat="article in articles | filter:activeFilter[filter]"
Controller:
$scope.filter = "name1";
$scope.activeFilter = {
name1: $scope.someFilterFunction,
name2: $scope.someOtherFilter,
name3: $scope.andAnother
};
$scope.someFilterFunction = function() {
var rv = [];
for (var p in items) {
if (items[p].myFilterProp === false)
rv.push(items[p]);
}
return rv;
};

Related

Angular - Filtering data based on bootstrap dropdown selection

I'm trying to filter a list based on a selection from a bootstrap dropdown, but cannot seem to get it to work. Here's my code:
<body>
<div class="toolbar-wrapper" >
<div class="btn-group container" role="group" ng-controller="filterController">
<div class="dropdown">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
{{filter}}
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li ng-repeat="severity in severityLevels">{{severity}}</li>
</ul>
</div>
</div>
</div>
<div class="logMessages" ng-controller="logController">
<div >
<ul>
<li class="message" ng-repeat="logData in data | filter: filter | limitTo: quantity">
{{logData.timestamp}} : {{logData.severity}} : {{logData.message}}
</li>
</ul>
</div>
</div>
</body>
Javascript:
var app = angular.module('UnifyLog', []);
app.controller('filterController', function($scope) {
$scope.severityLevels = [
'ERROR',
'WARN',
'INFO',
'DEBUG'
];
$scope.filter = '';
$scope.resetFilter = function() {
$scope.filter = '';
};
$scope.changeSeverity = function(severity) {
$scope.filter = severity;
}
})
.controller('logController', function ($scope, $http) {
$http.get("https://clock/settings/get_log_messages", {}).then(
function (response) {
$scope.data = response.data;
},
function (response) {
console.log("fail:" + response);
}
);
$scope.quantity=100
});
I know you can use ng-model data binding with a select directive, but I want to use a bootstrap dropdown.
The code above is updating the scope.filter variable but the list of log messages does not filter.
The http request is getting back a json array with log data objects containing message, timestamp, and severity fields.
Try calling $scope.apply():
$scope.changeSeverity = function(severity) {
$scope.filter = severity;
$scope.apply()
}
Look here for more information, and consider another approach (use real data-binding instead of a custom callback): https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply()
I would create a customer severity filter like so:
.filter('severityFilter', function () {
return function (input, severity) {
var out = [];
if (input && input != []) {
angular.forEach(input, function (thing) {
if(thing.severity === severity){
out.push(thing);
}
});
}
return out;
}
})
Then apply it like this:
ng-repeat="logData in data | severityFilter: severity | limitTo: quantity">

How to pass the values of a list as arguments of function in angularjs

HTML code
In the second controller when I am trying to show the values in "itemBought List" on click of button its rendering empty string for name and quantity while I have data for the same in itemToBuy.itemList".
It seems the datas for name and quantity are not passed into the addItemToBoughtList() function. How to achieve that.
<!-- To Buy List -->
<div class="col-md-6" ng-controller="ToBuyController as itemToBuy">
<h2>To Buy:</h2>
<ul>
<li ng-repeat="item in itemToBuy.itemList"> Buy {{item.itemQuantity}} of {{item.itemName}}
<button class="btn btn-default" ng-click="itemToBuy.addItemToBoughtList()"><span class="glyphicon glyphicon-ok"></span> Bought</button></li>
</ul>
<div class="emptyMessage">Everything is bought!</div>
</div>
<!-- Already Bought List -->
<div class="col-md-6" ng-controller="AlreadyBoughtController as itemBought">
<h2>Already Bought:</h2>
<ul>
<li ng-repeat="item in itemBought.items">
Bought {{ items.quantity }} of {{ item.name }}</li>
</ul>
<div class="emptyMessage">Nothing bought yet.</div>
</div>
</div>
Javascript code
(function (){
'use strict';
angular.module('ShoppingListCheckOff', [])
.controller('ToBuyController', ToBuyController)
.controller('AlreadyBoughtController', AlreadyBoughtController)
.service('ShoppingListCheckOffService',ShoppingListCheckOffService);
ToBuyController.$inject = ['ShoppingListCheckOffService'];
function ToBuyController(ShoppingListCheckOffService) {
var itemToBuy= this;
itemToBuy.itemName = "";
itemToBuy.itemQuantity = "";
itemToBuy.itemList = [
{itemName : 'cookies', itemQuantity : 10},
{itemName : 'napkins', itemQuantity : 15}
];
itemToBuy.addItemToBoughtList = function () {
ShoppingListCheckOffService.addItemToBoughtList(itemToBuy.itemName, itemToBuy.itemQuantity);
}
}
AlreadyBoughtController.$inject = ['ShoppingListCheckOffService'];
function AlreadyBoughtController(ShoppingListCheckOffService) {
var itemBought = this;
itemBought.name="";
itemBought.items = ShoppingListCheckOffService.getItems();
}
function ShoppingListCheckOffService() {
var service = this;
// List of shopping items
var items = [];
service.addItemToBoughtList = function (itemName, quantity) {
var item = {
name: itemName,
quantity: quantity
};
items.push(item);
};
service.getItems = function ()
return items;
};
}
})();
Pass Item to your addItemToBoughtList function
<ul>
<li ng-repeat="item in itemToBuy.itemList"> Buy {{item.itemQuantity}} of {{item.itemName}}
<button class="btn btn-default" ng-click="itemToBuy.addItemToBoughtList(item)"><span class="glyphicon glyphicon-ok"></span> Bought</button></li>
</ul>
and receive it in your function in js
itemToBuy.addItemToBoughtList = function (item) {
ShoppingListCheckOffService.addItemToBoughtList(item.itemName, item.itemQuantity);
}
I have created a plunker with your code. It is working fine, have a look

AngularJS nested loops - how do i get to not display an item when a condition fails in an inner ng-repeat loop

Say I have a nested loop like the code below
<div ng-repeat="m in masters">
<h3> {{m.name}} </h3>
<div ng-repeat="i in items">
<a ng-if="m.url === i.url"> {{i.name}} </a>
</div> </div>
How do I get to not have line 3 <h3> ... </h3> display the name when the condition
<a ng-if"..."> ... </a> fails and return nothing.
use a function to test whether the child condition exists -- so in your controller add a function like:
$scope.itemsHasUrl = function(url) {
for(var i=0;i<$scope.items.length;i++) {
if($scope.items[i].url === url) return true;
}
return false;
}
then in the template
<div ng-repeat="m in masters">
<h3 ng-if"itemsHasUrl(m.url)"> {{m.name}} </h3>
<div ng-repeat="i in items">
<a ng-if="m.url === i.url"> {{i.name}} </a>
</div>
</div>
you may also want to look into filters as you may be able to use the same function to limit the items checked in the interior loop, or using angular-filters groupBy method to avoid a double-loop at all.
good luck!
You can add a function in your controller to check if one of the items has the given url
$scope.checkUrl = function(url, items) {
for (var i = 0; i < items.length; i++) {
if (items[i].url == url) return true;
}
return false;
}
in your template
<h3 ng-if="checkUrl(m.url, items)"> {{m.name}} </h3>
To entertain my original comment, and derelict's answer, here is a .filter() way of doing this.
HTML
<div ng-repeat="m in masters | checkUrl:items">
<h3>{{m.name}}</h3>
<div ng-repeat="i in items | checkUrl:m">
<a>{{i.name}}</a>
</div>
</div>
Javascript
var app = angular.module("myApp", [])
.filter("checkUrl", function () {
return function (items, checkValues) {
return items.filter(function (item) {
if (typeof(checkValues.url) === "string") {
// single item check
return item.url === checkValues.url;
}
// else multiple items check
return checkValues.some(function (value) {
return value.url === item.url;
});
});
};
})
.controller("myCtrl", function ($scope) {
// controller code here ...
}

ng-repeat store separate values

I want to store the users vote's inside a cookie, the problem is that inside the ng-repeat I have a value called session.upVoteCount. But it is supposed to be a separate value for each event list item. Is it possible to store each upVoteCount separately and then retrieve them separately again?
<li ng-repeat="session in event.sessions | filter:query | orderBy:sortorder" class="span11">
<div class="row session">
<div class="col-sm-1 well votingWidget">
<div class="votingButton" ng-click="upVoteSession(session)">
<span class="glyphicon glyphicon-arrow-up"></span>
</div>
<div class="badge badge-inverse">
<div>{{session.upVoteCount}}</div>
</div>
<div class="votingButton" ng-click="downVoteSession(session)">
<span class="glyphicon glyphicon-arrow-down"></span>
</div>
</div>
</div>
</li>
and in my controller I have this:
$scope.upVoteSession = function(session) {
session.upVoteCount++;
};
$scope.downVoteSession = function(session) {
session.upVoteCount--;
};
First, I don't recommend to use term 'session', but 'votes'. However, it's your call.
I simplify your problem in this example
http://plnkr.co/edit/l7tQRbuOtEDJetY5eTsf?p=preview
Javascript:
function MyCtrl($scope) {
$scope.votes = {};
$scope.vote = function(key, val) {
$scope.votes[key] = $scope.votes[key] || 0;
$scope.votes[key]+= val;
};
}
Html:
<li ng-repeat="no in [1,2,3,4,5]">
{{no}} : {{votes[no]}} <br/>
upvote
downvote
</li>
Hi guys I solved it myself, I could not get it to work with JSfiddle so I have uploaded the entire thing. Click on server.bat and browser to localhost:8000/eventdetails.html and you will see it working.
https://mega.co.nz/#!1d9yiYiA!zTzdztLAmhVDVYOvvVLINETI2bo_WjxCBteWYm2VUKc
controller:
eventsApp.controller('EventController',
function EventController($scope, $cookieStore, eventData) {
$scope.sortorder = 'name';
var ape = eventData.getEvent();
ape.then(function (banana) {
$scope.event = banana;
angular.forEach(banana.sessions, function (value, key) {
var storecookie = ($cookieStore.get(value.name));
if (typeof storecookie !== "undefined") {
value.upVoteCount = storecookie;
}
});
});
$scope.upVoteSession = function (session) {
session.upVoteCount++;
$cookieStore.put(session.name, session.upVoteCount);
};
$scope.downVoteSession = function (session) {
session.upVoteCount--;
$cookieStore.put(session.name, session.upVoteCount);
};
}
);

AngularJS - Using a custom filter and ngClick to update same ng-repeat

I have a simple ng-repeat. The ng-reapeat can be populated in 2 ways, firstly by typing a value and clicking the Submit button, secondly, entering values and the list automatically updates.
The issue i am finding is that when a user clicks on Sumbit, the ng-repeat that uses the filter does not update.
Heres a plunker (type Help): http://plnkr.co/edit/1qR6CucQdsGqYnVvk70A?p=preview
HTML:
<div id="fixed" directive-when-scrolled="loadMore()">
<ul>
<li ng-repeat="i in items | limitTo: limit | filter: search">{{ i.Title }}</li>
</ul>
</div>
<br>
<input ng-model="searchText">
<button ng-click="performSearch(searchText)">Submit</button>
<div>
<strong>Result Search onClick</strong>
<ul>
<li ng-repeat="item in filtered">
<p>{{ item.Title }}</p>
</li>
</ul>
</div>
JS:
app.controller('MainCtrl', function($scope, $filter) {
$scope.limit = 5;
var counter = 0;
$scope.loadMore = function() {
$scope.limit += 5;
};
$scope.loadMore();
$scope.performSearch = function(searchText) {
$scope.filtered = $filter('filter')($scope.items, $scope.search);
}
$scope.search = function (item){
if (!$scope.searchText)
return true;
if (item.Title.indexOf($scope.searchText)!=-1 || item.Title.indexOf($scope.searchText)!=-1) {
return true;
}
return false;
};
});
app.directive("directiveWhenScrolled", function() {
return function(scope, elm, attr) {
var raw = elm[0];
elm.bind('scroll', function() {
if (raw.scrollTop + raw.offsetHeight >= raw.scrollHeight) {
scope.$apply(attr.directiveWhenScrolled);
}
});
};
});
Any ideas how i can use a single ng-repeat that bot updates on Click and whilst a user types in values?
It's the model name you pass to filter
it's
<li ng-repeat="i in items | limitTo: limit | filter: search">{{ i.Title }}</li>
should be
<li ng-repeat="i in items | limitTo: limit | filter: searchText">{{ i.Title }}</li>

Resources