How to count the number of elements selected in a directive? - angularjs

If you have a career-box directive like this:
<div ng-repeat='career in careers' career-box ng-click="toggleSelected()"> {{ career.name }} </div>
The directive:
app.directive('careerBox', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
scope.selected = false,
scope.toggleSelected = function() {
element.toggleClass('selected');
if(scope.selected) {
scope.selected = false;
} else {
scope.selected = true;
}
}
}
};
});
Every time a career-box is selected I would like to count the total number of career-boxes selected (selected=true) and enable a button if they are more than 0.
How can I do that in the code?

There is no need to write a custom directive. It can be done with Angular core directives:
vm.selectedCount = function(item) {
var count=0;
for (let i=0; i<vm.careers.length; i++) {
if (vm.careers[i].selected) count++;
}
return count;
}
<div ng-repeat='career in careers'
ng-click="career.selected = !career.selected"
ng-style="{'background-color': career.selected?'yellow':''}">
{{ career.name }}
</div>
<hr>Selected count: {{selectedCount()}}
The DEMO on PLNKR
The DEMO
angular.module("myApp",[]);
angular.module("myApp").controller("myVm", function($scope) {
var vm = $scope;
vm.careers = [ {name: "Police Officer", value: 1},
{name: "Nurse", value:2},
{name: "Doctor", value:3},
];
vm.selectedCount = function(item) {
var count=0;
for (let i=0; i<vm.careers.length; i++) {
if (vm.careers[i].selected) count++;
}
return count;
}
})
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myApp" ng-controller="myVm">
<h1>Selected Div Example</h1>
<div ng-repeat='career in careers'
ng-click="career.selected = !career.selected"
ng-style="{'background-color': career.selected?'yellow':''}">
{{ career.name }}
</div>
<hr>Selected count: {{selectedCount()}}
</body>

First, you need to have a select element with the multiple property:
<select name="carers" multiple id="multipleCarers" ng-model="data.multipleCarers">
<option ng-repeat="career in careers" value="{{career.value}}">
{{career.name}}
</option>
</select>
After of that, you can get the count of options selected:
{{data.multipleCarers.length}}

Related

Angularjs Price Range Slider dynamically manipulate content based on Min-Max

I am new to AngularJS & I am using angular-slider for specifying a price range. I want to display the only elements specified by the range.
Here's the AngularJS Code-
var app = angular.module('myApp', ['rzModule']);
app.controller('SampleController', function($scope, $http) {
$scope.elements = [1530,2100,2780,3323,3420,4680,5020,5300,5402];
});
app.controller('RangeController', RangeController);
function RangeController() {
var vm = this;
vm.changeListener = function() {
minPrice = vm.slider.minValue;
maxPrice = vm.slider.maxValue;
console.log(minPrice + " " +maxPrice);
};
vm.slider = {
minValue: 1500,
maxValue: 5500,
options: {
floor: 1500,
ceil: 5500,
step: 500,
translate: function(value) {
return '₹' + value;
},
onChange:vm.changeListener
}
}
}
HTML-
<body ng-app="myApp">
<div ng-controller="RangeController as vm">
<rzslider rz-slider-model="vm.slider.minValue" rz-slider-high="vm.slider.maxValue" rz-slider-options="vm.slider.options"></rzslider>
</div>
<div ng-controller="SampleController">
<div ng-repeat="x in elements">
{{x}}
</div>
</div>
I think it can be done using filters but I am not sure. Any Solutions?
You can write a Custom AngularJS filter for this.
angular.module('myModule', [])
.filter('inRange', function() {
return function(array, min, max) {
array = array.filter(function(element) {
return element >= min && element <= max;
});
};
});
});
<div ng-repeat="x in elements | inRange:vm.slider.minValue:vm.slider.maxValue">

Angular Google Maps, Directive inside Info Window isn't binding data

I'm using Angular google Maps trying to get an info window working. When a marker is selected, the window is placed there and shown. Its content is some text and also some directives. The directives inside even work, except for when I try to bind some data its attributes.
In this case I'm having a rating directive (shows a bunch of stars) that takes a number attribute, as so:
<div stars number="person.rating"></div>
Note that this directives works just fine in a couple of other places in my app. Also, when I replace person.rating' for3, the directive renders perfectly. when I useperson.rating` outside of this div, it returns a number as expected.
Only when I combine the person.rating inside the number attribute, inside the window directive, do things go awry:
<ui-gmap-google-map center='map.center' class="big-maps" options='map.options' events="map.events" zoom='map.zoom'>
<ui-gmap-window coords="selectedCoords" show="windowOptions.visible" closeClick="closeWindow">
<div>
Name: {{person.firstName}}, Rating: {{person.rating}} <!-- these work just fine. -->
<div> So here we are. {{person.rating}}</div> <!-- this also works just fine. -->
<div stars number="3"></div> <!-- Even this works fine. -->
<div stars number="person.rating"></div> <!-- But this doesn't... -->
</div>
</ui-gmap-window>
<ui-gmap-markers
models='markers'
idKey='id'
coords="'coords'"
icon="'icon'"
options="'options'"
doCluster="false"
click="showWindow"
>
</ui-gmap-markers>
</ui-gmap-google-map>
The directive:
ndtApp.directive('stars', stars);
function stars() {
return {
restrict: "AE",
replace: 'true',
scope: {
number: "=",
size: "#"
},
templateUrl: "shared/stars/stars.html",
controller: controller
};
}
function controller($scope){
$scope.getEmptyStarsArray = getEmptyStarsArray;
$scope.getStarsArray = getStarsArray;
$scope.ratingSize = "";
activate();
function activate(){
if ($scope.size == 'sm'){
$scope.ratingSize = 'rating-sm';
} else if ($scope.size == 'lg'){
$scope.ratingSize = 'rating-lg';
}
console.log($scope.number);
}
function getEmptyStarsArray(){
if ($scope.number === undefined) return 0;
var rating = Math.round($scope.number);
if (rating > 4) return null;
return new Array(5 - rating);
}
function getStarsArray(){
if ($scope.number === undefined) return 0;
var rating = Math.round($scope.number);
if (rating === 0) return null;
if (rating > 5) return new Array(5);
return new Array(rating);
}
}
stars.html:
<div class="stars">
<span ng-repeat="i in getStarsArray() track by $index" class="{{ratingSize}} rating glyphicon glyphicon-star"></span><span ng-repeat="i in getEmptyStarsArray() track by $index" class="{{ratingSize}} rating glyphicon glyphicon-star-empty"></span>
</div>
Any help is highly appreciated!
It seems directive scope property is not getting bound, try to change scope for number property from number: "=" to number: "#" and directive initialization from <div stars number="person.rating"></div> to <div stars number="{{person.rating}}"></div>
Below is provided a working similar example:
var appMaps = angular.module('appMaps', ['uiGmapgoogle-maps']);
appMaps.controller('mainCtrl', function($scope,uiGmapIsReady) {
$scope.map = {
center: { latitude: 40.1451, longitude: -99.6680 },
zoom: 4,
options: { scrollwheel: false }
};
$scope.windowOptions = { visible: false };
var getRandomLat = function() {
return Math.random() * (90.0 + 90.0) - 90.0;
};
var getRandomLng = function () {
return Math.random() * (180.0 + 180.0) - 180.0;
};
var getRandomRating = function() {
return Math.floor(Math.random() * 11);
};
var createRandomMarker = function(i) {
var ret = {
latitude: getRandomLat(),
longitude: getRandomLng(),
title: 'Hotel #' + i,
show: false,
id: i
};
return ret;
};
$scope.onClick = function(marker, eventName, model) {
$scope.windowOptions.visible = true;
$scope.selectedHotel = model;
$scope.rating = { number: getRandomRating()};
};
$scope.closeWindow = function () {
$scope.windowOptions.visible = false;
};
$scope.hotels = [];
for (var i = 0; i < 256; i++) {
$scope.hotels.push(createRandomMarker(i));
}
});
appMaps.directive('rating',
function() {
return {
restrict: "AE",
replace: true,
scope: {
//number: "=",
number: "#"
},
controller: ratingController,
//template: '<div >Rating: {{ ::number }}</div>',
template: function(tElem, tAttrs){
return '<div class="rating"> Rating:' + tAttrs.number + '</div>';
}
};
});
function ratingController($scope){
console.log($scope.number);
}
html, body, #map_canvas {
height: 100%;
width: 100%;
margin: 0px;
}
#map_canvas {
position: relative;
}
.angular-google-map-container {
position: absolute;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
<script src="https://code.angularjs.org/1.3.14/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.js"></script>
<script src="http://rawgit.com/angular-ui/angular-google-maps/2.0.X/dist/angular-google-maps.js"></script>
<div id="map_canvas" ng-app="appMaps" ng-controller="mainCtrl">
<ui-gmap-google-map center="map.center" zoom="map.zoom" draggable="true" options="options" events="map.events">
<ui-gmap-window coords="selectedHotel" show="windowOptions.visible" closeclick="closeWindow">
<div>
<div>{{selectedHotel.title}}</div>
<div rating number="{{rating.number}}"></div>
</div>
</ui-gmap-window>
<ui-gmap-markers models="hotels" coords="'self'" icon="'icon'" click="onClick">
</ui-gmap-markers>
</ui-gmap-google-map>
</div>

Get height of div in angularjs

I have 3 div in which the data is filling from controller. and the div is dependent on dropdown select (particular div will be shown for particular dropdown value). the problem is that I am unable to get the height of that div when page is loaded and also when I changed the dropdown value. Everytime I am getting 0 height.
here is the code for html:
<div class="brand-categoryWrp">
<select ng-model="allbrandscategory" ng-change="catChange(allbrandscategory)">
<option value="all">AllBrands</option>
<option value="watches">Watches</option>
<option value="pens">Pens</option>
</select>
</div>
<div ng-show="firstdiv" allbrands-directive>
<ul>
<li ng-repeat="res in brands">
{{res.name}}
</li>
</ul>
</div>
<div ng-show="seconddiv" watches-directive>
<ul>
<li ng-repeat="res in brands1">
{{res.name}}
</li>
</ul>
</div>
<div ng-show="thirddiv" pens-directive>
<ul>
<li ng-repeat="res in brands2">
{{res.name}}
</li>
</ul>
</div>
and here is for controller:
// Code goes here
var myapp = angular.module('myModule', []);
myapp.controller('mycntrl',function($scope){
$scope.allbrandscategory = 'all';
$scope.firstdiv = true;
$scope.brands = [
{name: 'Adidas'},
{name: 'Armani'}
];
$scope.brands1 = [
{name: 'Adidas1'},
{name: 'Armani1'},
{name: 'Fossil'}
];
$scope.brands2 = [
{name: 'Adidas2'},
{name: 'Armani2'},
{name: 'Mont blanc'},
{name: 'calvin'}
];
$scope.catChange = function(val){
$scope.firstdiv = false;
$scope.seconddiv = false;
$scope.thirddiv = false;
if(val == 'all')
{
$scope.firstdiv = true;
}
else if(val == 'watches')
{
$scope.seconddiv = true;
}
else if(val == 'pens')
{
$scope.thirddiv = true;
}
};
});
myapp.directive('pensDirective', function($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
//console.log(element);
console.log("pens: "+element[0].offsetHeight);
}
};
});
myapp.directive('watchesDirective', function($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
// console.log(element);
console.log('watches: '+element[0].offsetHeight);
}
};
});
myapp.directive('allbrandsDirective', function($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
//console.log(element);
console.log("brand: "+element[0].offsetHeight);
}
};
});
Here is the plunker
The link function is executed before the model data is bound to the view (the div does not contain any child elements when you're requesting the offsetHeight. Try wrapping it into a $timeout(function() { /* ... */ }), which will execute at the end of the current digest cycle.
Check out AngularJs event to call after content is loaded
This has a nice answer to your problem and seems to work. Second answer down.
I tested on yours by adding the below to your allbranddirective:
element.ready(function(){
console.log("brand: "+element[0].offsetHeight);
});
EDIT:
HTML:
<html>
<div class="brand-categoryWrp">
<select ng-model="divtoshow" ng-change="catChange(divtoshow)">
<option value="allbrands-directive">AllBrands</option>
<option value="watches-directive">Watches</option>
<option value="pens-directive">Pens</option>
</select>
</div>
<div allbrands-directive><ul><li ng-repeat='res in brands'>{{res.name}}</li></ul></div>
JS:
var myapp = angular.module('myModule', []);
myapp.controller('mycntrl',function($scope){
$scope.brands = [{name: 'Adidas'}, {name: 'Armani'}];
$scope.divtoshow = 'allbrands-directive'
$scope.catChange = function(val){
$scope.divtoshow = val;
if (val == 'allbrands-directive'){
$scope.brands = [{name: 'Adidas'}, {name: 'Armani'}];
}else if (val == 'watches-directive') {
$scope.brands = [{name: 'Adidas1'},{name: 'Armani1'},{name: 'Fossil'}];
}else if (val == 'pens-directive') {
$scope.brands = [{name: 'Adidas2'},{name: 'Armani2'},{name: 'Mont blanc'},{name: 'calvin'}];
}
}
});
myapp.directive('allbrandsDirective', function($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
scope.$watch('brands', function(){
console.log("brand: "+element[0].offsetHeight);
});
}
};
});
So I have changed your code a bit, I have set up only one directive and in here I watch on a change of the brands variable, when this changes we then get the height of the element.
See plunker - http://plnkr.co/edit/vZhn2aMRI6wKn3yVharS?p=preview
If you need each section in separate directives see nulls answers

AngularJS: How to refresh $viewValue even when $modelValue is unchanged

In the example below, the value in input 'ia' can get out of sync with the model value (e.g. if you type in 'aaa'). What I would like to achieve is when the input 'ia' loses focus, update its value to the formatted value of the current model value (e.g. when model value is null, update the view value to string 'N/A'). Anybody know I this might be achieved? Thanks.
The current behaviour is if you type in 'aaa' as profession, model value is updated to null bot 'aaa' stays in the input.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script>
var myapp = angular.module('myapp', []);
myapp.controller('mycontroller', function($scope) {
$scope.model = {
name: "ttt",
age: 24,
profession: null
};
});
var professionList = [{
id: 1,
name: "p1"
}, {
id: 2,
name: "p2"
}, {
id: 3,
name: "p3"
}, {
id: 4,
name: "p4"
}];
myapp.directive("prof", function() {
return {
restrict: 'A',
require: 'ngModel',
link: function(scope, element, attrs, ngModel) {
ngModel.$formatters.push(function(value) {
for (var i = 0; i < professionList.length; i++) {
if (value == professionList[i].id)
return professionList[i].name;
}
return "N/A";
});
//format text from the user (view to model)
ngModel.$parsers.push(function(value) {
for (var i = 0; i < professionList.length; i++) {
if (value == professionList[i].name)
return professionList[i].id;
}
return null;
});
element[0].ngModel = ngModel;
}
};
});
</script>
</head>
<body ng-controller="mycontroller">
<form>
Name:
<input ng-model="model.name" />
<br />Age:
<input ng-model="model.age" />
<br />Profession:
<input prof="" ng-model="model.profession" id="ia" />
<input ng-model="model.profession" />
</form>
<hr />Name: {{model.name}}
<br />Age: {{model.age}}
<br />Profession: {{model.profession}}
</body>
</html>
UPDATE:
I found a solution based on the answer in this question
//add this to the link function:
ngModel.$render = function(){
element[0].value = ngModel.$viewValue;
};
element[0].onblur = function(){
var viewValue = ngModel.$modelValue;
for (var i in ngModel.$formatters) {
viewValue = ngModel.$formatters[i](viewValue);
}
ngModel.$viewValue = viewValue;
ngModel.$render();
};
While returning null you are not re-initializing ngModel and I dont think directive is needed here , there is something called ng-blur in angularjs,
Profession : <input ng-model="model.profession" ng-blur="checkProfession() "/>
Profession ID : <input ng-model="model.id" />
In your controller write a function as,
$scope.checkProfession=function(){
var flag=0;
for (var i = 0; i < professionList.length; i++) {
if ($scope.model.profession == professionList[i].name){
$scope.model.id=professionList[i].id;
flag=1;
}
if(!flag){
$scope.model.id="";
$scope.model.profession="";
}
}
}

AngulajrJS filter output html

Hi I am writing a filter which takes and array and returns a comma delimited string.
When i append some HTML it is not showing in the output.
Below is my code
$scope.authors = [{ "authorName": 'Robin', "price": 40, "link": 'http://www.google.com' },
{ "authorName": 'Chetan', "price": 400, "link": 'http://www.bing.com' },
{ "authorName": 'Jack Wilson', "price": 450, "link": 'http://www.facebook.com'}
]
My Filter
myApp.filter('formatAuthorName', function () {
return function (input) {
var str = [];
var totalString = '';
if (input.length > 1) {
for (var i = 0; i < input.length; i++) {
var name = input[i];
**str.push('<a href='**name.link**'>'+name.authorName+'</a>');**
}
totalString = str.join(', ');
return totalString;
}
return totalString;
};
});
Also how to bind href to link from Scope ??.
Thanks
For outputting HTML that interacts with scope, a directive is more suitable than a filter.
This answer expands on the solution originally proposed by ajk.
Demo Plunker
Directive
app.directive('formatAuthorNames', function() {
return {
restrict: 'A',
scope: { authors: '=' },
template:
'<span ng-repeat="author in authors">
<a ng-href="{{ author.link }}">{{ author.authorName }}</a>
<span ng-if="$index < authors.length-1">, </span>
</span>',
link: function(scope, elem, attr) {
// access scope here
}
}
});
HTML
<body ng-app="app" ng-controller='MyController'>
<div authors="authors" format-author-names></div>
</body>
Use $sce in your filter if you want to render html:
<div ng-bind-html="authors | formatAuthorName"></div>
JS:
app.filter('formatAuthorName', ['$sce',
function($sce) {
return function(input) {
var str = [];
var totalString = '';
if (input.length > 1) {
for (var i = 0; i < input.length; i++) {
var name = input[i];
str.push('<a href=' + name.link + '>' + name.authorName + '</a>');
}
totalString = str.join(', ');
}
return $sce.trustAsHtml(totalString);
};
}
]);
DEMO PLUNKER
I'm not sure that a filter is what you're actually looking for here. You will probably be better served by using ng-repeat in combination with ng-href. Something like this:
<div ng-repeat="author in authors">
<a ng-href="{{ author.link }}">{{ author.authorName }}</a>
</div>
try using ng-href instead of a filter
https://docs.angularjs.org/api/ng/directive/ngHref
Hope this helps.

Resources