Angular Radio Button Not Firing On Watch - angularjs

I have a watch on region but it is not firing when I click on the radio button.
Am I doing something wrong or is it because radio buttons only detect change once in angular? Anyway around this without using form?
<div class="filter-column">
<div class="filter-title">Region</div>
<div class="bottom-line"></div>
<div class="overflow-container">
<div ng-repeat="choice in regions| orderBy: 'description'">
<input type="radio"
value="{{choice.name}}"
name="regionRadio"
ng-model="region">
{{choice.description}}
</div>
</div>
</div>
$scope.$watchCollection(watchRMDapisPopulate,
populateRMDfiltersView);
function watchRMDapisPopulate() {
return regionMarketDealerSrv.orgFilterData;
}
function populateRMDfiltersView(newValue, oldValue) {
if (newValue) {
$scope.regions = newValue.regions;
}
}
$scope.$watch('region', radioButtonRegion);
function radioButtonRegion(regionName) {
console.log(regionName)
if (regionName === 'All') {
regionMarketDealerSrv.populateRegions();
} else {
regionMarketDealerSrv.populateMarkets(regionName);
}
}

The watch isn't able to pick up the changes correctly when using ng-model="region" since you are using primitive values. When you change the value you are getting a new reference. You can use a property of an object as your model and $watch that:
var app = angular.module('app', [])
app.controller('MyController', function($scope) {
$scope.regions = [{
name: 'a',
description: 'region A'
}, {
name: 'b',
description: 'region B'
}];
$scope.selected = {
region: 'a'
};
$scope.$watch('selected.region', radioButtonRegion);
function radioButtonRegion(newVal, oldVal) {
if (newVal !== oldVal) {
console.log(newVal, oldVal)
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="MyController">
<div>Region</div>
<div ng-repeat="choice in regions| orderBy: 'description'">
<input type="radio" value="{{choice.name}}" name="regionRadio" ng-model="selected.region">{{choice.description}}
</div>
</div>

Related

add green background to the label that contains the selected radio input

I am new at angular. I would like that by clicking on the selected radio input, the label turns green. How can I do it?
<div ng-app="myApp">
<div ng-controller="myController">
<div>Which one?</div>
<label class="radio" ng-repeat="eval in evaluators">
<input type="radio" ng-model="cell.evaluator" name="evaluatorOptions" value="{{eval.name}}">{{eval.name}}
</label>
<hr />
<div>You picked: {{cell.evaluator}}</div>
</div>
</div>
var app = angular.module('myApp', []);
app.controller('myController', function ($scope) {
$scope.cell = {
evaluator: "Guava2"
};
$scope.evaluators = [{
name: "Guava1"
}, {
name: "Guava2"
}];
});
http://jsfiddle.net/77axwybr/
You can use ng-class to dynamically set the class of the label using a method on scope that checks the current value with that set in ng-model.
<style>
.selected {
background: green;
}
</style>
<div ng-app="myApp">
<div ng-controller="myController">
<div>Which one?</div>
<label ng-class="{selected: isSelected(eval.name) }" class="radio" ng-repeat="eval in evaluators">
<input type="radio" ng-model="cell.evaluator" name="evaluatorOptions" value="{{eval.name}}">{{eval.name}}
</label>
<hr />
<div>You picked: {{cell.evaluator}}</div>
</div>
</div>
var app = angular.module('myApp', []);
app.controller('myController', function ($scope) {
$scope.isSelected = (name) => $scope.cell.evaluator === name;
$scope.cell = {
evaluator: "Guava2"
};
$scope.evaluators = [{
name: "Guava1"
}, {
name: "Guava2"
}];
});
http://jsfiddle.net/vsdvcepn/

Angular: How to $broadcast from Factory?

I have a list of items and I need to get a message (saying Item added!) in the navbar whenever a new item is added.
The function addItem() (ng-click on the Add Item button) is in the ItemFactory and from there I seem to not be able to broadcast it.
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
</head>
<body ng-app="MyApp" ng-controller="MainCtrl">
<div>{{ text }}
<nav class="navbar navbar-inverse" ng-controller="NavCtrl">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">List of items | {{ alertItemAdded }}</a>
</div>
<form class="navbar-form navbar-right" role="search">
<div class="form-group">
<input type="text" class="form-control" ng-model="newItem" placeholder="Add an item">
</div>
<button type="submit" class="btn btn-primary" ng-click="addItem(newItem)">Add Item</button>
</form>
</div>
</nav>
<div class="container" ng-controller="ContentCtrl">
<div class="row">
<div class="col-xs-12">
<form class="form-inline">
<div class="form-group">
<input type="text" class="form-control" ng-model="newItem" placeholder="Add an item">
</div>
<button type="submit" class="btn btn-primary" ng-click="addItem(newItem)">Add Item</button>
</form>
<br />
<br />
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div ng-repeat="item in items">
<form class="form-inline">
<div class="form-group">
<div>{{ item }}</div>
</div>
<button type="button" class="btn btn-default btn-s" ng-click="removeItem($index)">Remove Item</button>
</form>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
angular.module('MyApp',[]);
angular.module('MyApp').controller('MainCtrl', function($scope, ItemFactory){
$scope.text = "Text from the Main Controller";
$scope.addItem = function(newItem){
ItemFactory.addItem(newItem);
}
});
angular.module('MyApp').controller('NavCtrl', function($scope){
// $on
$scope.$on('itemAdded', function(event, data){
$scope.alertItemAdded = data;
});
});
angular.module('MyApp').controller('ContentCtrl', function($scope, ItemFactory){
$scope.items = ItemFactory.getItem();
$scope.removeItem = function($index){
ItemFactory.removeItem($index);
}
});
angular.module('MyApp').factory('ItemFactory', function(){
var items = [
'Item 1',
'Item 2',
'Item 3'
];
return {
getItem : function() {
return items;
},
addItem : function(item){
items.push(item);
// $broadcast
$scope.$broadcast('itemAdded', 'Item added!');
},
removeItem : function($index){
items.splice($index, 1);
}
};
});
You can inject $rootScope into your factory and use $broadcast from there.
angular.module('MyApp').factory('ItemFactory', ["$rootScope", function($rootScope){
var items = [
'Item 1',
'Item 2',
'Item 3'
];
return {
getItem : function() {
return items;
},
addItem : function(item){
items.push(item);
// $broadcast
$rootScope.$broadcast('itemAdded', 'Item added!');
},
removeItem : function($index){
items.splice($index, 1);
}
};
}]);
Here is a clean solution for you.
See it working in this plunker
Let me explain how all of this works.
Your message looks like this :
<span ng-if="alertItemAdded.recentAdd">Item added !</span>
It will show only when "alterITemAdded.recenAdd" is true. You'll use this to make the message disapear if you need.
You factory look like this now :
angular.module('MyApp').service('ItemService', function(){
var service = {};
//I'll always wrap my data in a sub object.
service.notification = {};
service.notification.recentAdd=false;
service.items = {};
service.items.list = [
'Item 1',
'Item 2',
'Item 3'
];
service.items.addItem = function(item){
service.items.list.push(item);
service.notification.recentAdd=true;
console.log(service);
}
service.items.removeItem = function($index){
service.items.list.splice($index, 1);
}
return service;
});
I'm using service instead of factory. But there is almost no difference, it's just a matter of taste.
Here is your controllers
angular.module('MyApp').controller('MainCtrl', function($scope, ItemService){
$scope.text = "Text from the Main Controller";
});
angular.module('MyApp').controller('NavCtrl', function($scope, ItemService){
//IMPORTANT POINT : I bind it the sub object. Not to the value. To access the value i'll use $scope.alterItemAdded.recentAdd
$scope.alertItemAdded = ItemService.notification;
//I don't have to redeclare the function. I just bind it to the service function.
$scope.addItem = ItemService.items.addItem;
});
angular.module('MyApp').controller('ContentCtrl', function($scope, ItemService){
$scope.items = ItemService.items.list;
$scope.addItem = ItemService.items.addItem;
$scope.removeItem = function($index){
ItemService.items.removeItem($index);
}
});
Important point :
I always bind my vars to a sub object. Why ? In fact if i did
$scope.alertItemAdded = ItemService.notifications.recentAdd
When i do something like this in my service
service.notifications.recentAdd = true;
It will create a new variable and put the reference into service.notifications.recentAdd. The $scope.alertItemAdded was bind to the previous reference and wont see the update.
Doing this :
$scope.alterItemAdded = ItemService.notification
And using the value in the ng-if clause or anything else. I prevent the reference link to break. If i do in the service
service.notification.recentAdd = true
I'll create a new var with a new reference for "recentAdd" but i keep the same reference for "notification". The binding in the controller will be keep and the value recentAdd will be updated in the view.
If you have more question feel free to ask.
You not injected $scope to factory, and you cant actually, use $rootScope instead
$broadcast goes from top to bottom so you should use $rootScope to perform a $broadcast to all $scope elements below it.
Inject $rootScope in your factory
$rootScope.$broadcast('itemAdded, 'Item added!')

Enable button when i have selected two values

I have two select i want to enable my button when i have selected values in my two select, i don't know how i can do this ?
JSFIDDLE
My HTML:
<div ng-app="myapp">
<fieldset ng-controller="FirstCtrl">
<select
ng-options="people.first for people in people_1"
ng-model="selectedPerson1"></select>
<select
ng-options="people.first for people in people_2"
ng-model="selectedPerson2"></select>
</fieldset>
<br/><button class="btn btn-primary" ng-click="platform=true">Comparer</button>
</div>
You can do this using the ng-disabled directive. I have amended your jsfiddle here: http://jsfiddle.net/p0t4cw84/3/. I moved the button into the scope of the controller FirstCtrl and added a method on the scope that will return true or false if values are selected.
$scope.enableCompare = function () {
return !($scope.selectedPerson1 && $scope.selectedPerson2);
};
I hope this helps.
Here you go.There are lot of issue in you fiddle.I fixed it.
http://jsfiddle.net/purpz7u3/
<div ng-app="myapp">
<div ng-controller="FirstCtrl">
<fieldset >
<select
ng-options="people.first for people in people_1"
ng-model="selectedPerson1" ng-change="check()"></select>
<select
ng-options="people.first for people in people_2"
ng-model="selectedPerson2" ng-change="check()"></select>
</fieldset>
<br/><button class="btn btn-primary" ng-disabled="checked">Comparer</button>
</div>
</div>
var myapp = angular.module('myapp', []);
myapp.controller('FirstCtrl', function ($scope) {
$scope.checked = true;
$scope.people_1 = [
{ id: 1, first: 'John' },
{ id: 2, first: 'Rocky' }
];
$scope.people_2 = [
{ id: 1, first: 'Rambo' },
{ id: 2, first: 'Balboa'}
];
$scope.check = function(){
if($scope.selectedPerson1 && $scope.selectedPerson2){
$scope.checked=false;
}
}
});

Why won't my view template bind to a scope variable with AngularJS?

My view is:
<div class="container" ng-controller="MyController">
<div class="row">
<div class="col-md-8">
<textarea class="form-control" rows="10" ng-model="myWords" ng-change="parseLanguage()"></textarea>
</div>
<div class="col-md-4" ng-show="sourceLanguage !== null">
Language: {{ sourceLanguage }}
</div>
</div>
</div>
My controller is:
webApp.controller('MyController', [
'$scope', '$rootScope', 'TranslateService', function($scope, $rootScope, CodeService) {
$scope.init = function() {
return $scope.sourceLanguage = null;
};
$scope.parseLanguage = function() {
return TranslateService.detectLanguage($scope.myWords).then(function(response) {
console.log($scope.sourceLanguage);
$scope.sourceLanguage = response.data.sourceLanguage;
return console.log($scope.sourceLanguage);
});
};
return $scope.init();
}
]);
The console logs show the right data. But in the view, sourceLanguage never updates. Why would this be?
In case the promise you are evaluating is not part of the Angular context you need to use $scope.$apply:
$scope.parseLanguage = function() {
TranslateService.detectLanguage($scope.myWords).then(function(response) {
$scope.$apply(function() {
$scope.sourceLanguage = response.data.sourceLanguage;
});
});
};

How to $watch changes on models created by ng-repeat?

Consider this Plnkr for example. I don't know how many members of fooCollection will be created beforehand. So I don't know how many bar models are going to exist.
But I know they are going to be angular models, and I know where they are going to be.
How do I do a $watch on these?
I need to do that because I need to trigger behavior when a bar model is changed. Watching the fooCollection itself is not enough, the $watch listener does not fire when a bar is changed.
Relevant html:
<body ng-controller="testCtrl">
<div ng-repeat="(fooKey, foo) in fooCollection">
Tell me your name: <input ng-model="foo.bar">
<br />
Hello, my name is {{ foo.bar }}
</div>
<button ng-click="fooCollection.push([])">Add a Namer</button>
</body>
Relevant JS:
angular
.module('testApp', [])
.controller('testCtrl', function ($scope) {
$scope.fooCollection = [];
$scope.$watch('fooCollection', function (oldValue, newValue) {
if (newValue != oldValue)
console.log(oldValue, newValue);
});
});
Create individual list-item controllers: demo on Plnkr
js
angular
.module('testApp', [])
.controller('testCtrl', function ($scope) {
$scope.fooCollection = [];
})
.controller('fooCtrl', function ($scope) {
$scope.$watch('foo.bar', function (newValue, oldValue) {
console.log('watch fired, new value: ' + newValue);
});
});
HTML
<html ng-app="testApp">
<body ng-controller="testCtrl">
<div ng-repeat="(fooKey, foo) in fooCollection" ng-controller="fooCtrl">
Tell me your name: <input ng-model="foo.bar" ng-change="doSomething()">
<br />
Hello, my name is {{ foo.bar }}
</div>
<button ng-click="fooCollection.push([])">Add a Namer</button>
</body>
</html>
If you have your collection populated, you can place a watch on each item of the ng-repeat:
html
<div ng-repeat="item in items">
{{ item.itemField }}
</div>
js
for (var i = 0; i < $scope.items.length; i++) {
$scope.$watch('items[' + i + ']', function (newValue, oldValue) {
console.log(newValue.itemField + ":::" + oldValue.itemField);
}, true);
}
You can pass true as third argument into $watch
$scope.$watch('something', function() { doSomething(); }, true);
https://docs.angularjs.org/api/ng/type/$rootScope.Scope
You can also create a custom directive that will tell your main controller for the changes
YourModule.directive("batchWatch",[function(){
return {
scope:"=",
replace:false,
link:function($scope,$element,$attrs,Controller){
$scope.$watch('h',function(newVal,oldVal){
if(newVal !== oldVal){
Controller.updateChange(newVal,oldVal,$scope.$parent.$index);
}
},true);
},
controller:"yourController"
};
}]);
assume your markup is like this
<ul>
<li ng-repeat="h in complicatedArrayOfObjects">
<input type="text" ng-model="someModel" batch-watch="$index" />
</li>
</ul>
and this is your controller
YourModule.controller("yourController",[$scope,function($scope){
this.updateChange = function(newVal,oldVal,indexChanged){
console.log("Details about the change");
}
}]);
You can also play around the value provided by the directive link function which sits on first 3 arguments, scope,element and attr.
Since I didn't want another controller I ended up using ng-change instead.
Simple jsFiddle: https://jsfiddle.net/maistho/z0xazw5n/
Relevant HTML:
<body ng-app="testApp" ng-controller="testCtrl">
<div ng-repeat="foo in fooCollection">Tell me your name:
<input ng-model="foo.bar" ng-change="fooChanged(foo)">
<br />Hello, my name is {{foo.bar}}</div>
<button ng-click="fooCollection.push({})">Add a Namer</button>
</body>
Relevant JS:
angular.module('testApp', [])
.controller('testCtrl', function ($scope) {
$scope.fooCollection = [];
$scope.fooChanged = function (foo) {
console.log('foo.bar changed, new value of foo.bar is: ', foo.bar);
};
});
Try to do this
<div ng-repeat="foo in fooCollection" ng-click="select(foo)">Tell me your ame:
<input ng-model="foo.bar" ng-change="fooChanged(foo)">
<br />Hello, my name is {{foo.bar}}</div>
<button ng-click="fooCollection.push({})">Add a Namer</button>
</div>
There is the code in Directive/Controller
$scope.selectedfoo = {};
$scope.select = (foo) => {
$scope.selectedfoo = foo;
}
$scope.$watch('selectedfoo ', (newVal, oldVal) => {
if (newVal) {
}
},true)

Resources