Bind search input to ng-repeat in different controller - angularjs

I am building a web application using Angular. We have a Twitter-like navigation bar up top with a search box in it. Then we have a bunch of entries below, using the ng-repeat directive. I want to be able to bind the search box with the entries below. The challenge is due to the fact that our header and our entries are in two different controllers. If they were in the same controller, then we could do this:
<input type="search" ng-model="search">
<div ng-repeat="entry in entries | filter:search">
{{ entry.text }}
</div>
But since in my application the search box is in a different controller, search isn't in scope so it's not working.
Any suggestions?

If you put the search string inside a service you can share the data between both controllers.
Here is an example.
<!doctype html>
<html ng-app="app">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
<script>
angular.module('app', []);
angular.module('app')
.controller('Ctrl1', function($scope, ShareData) {
$scope.myData1 = ShareData;
});
angular.module('app')
.controller('Ctrl2', function($scope, ShareData) {
$scope.myData2 = ShareData;
$scope.entries = [
'1',
'2',
'3',
'11'
]
});
angular.module('app')
.service('ShareData', function(){
return {
search: "1"
}
})
</script>
</head>
<body >
<div ng-controller="Ctrl1">
<h2>Inside Ctrl 1</h2>
<input type="text" ng-model="myData1.search">
</div>
<hr>
<div ng-controller="Ctrl2">
<h2>Inside Ctrl 2</h2>
<div ng-repeat="entry in entries | filter:myData2.search">
{{entry}}
</div>
</div>
</body>
</html>

You can do one thing use $emit on rootscope and capture it in another controller:-
For example:-
<input type="search" ng-model="search">
Controller one:-
$scope.$watch('search',function(new){
$rootScope.$emit('update',new);
});
Controller Second:-
$rootScope.$on('update', function (event, data) {
$scope.search=data;
});
Secondly you can also share data from controller's via service (this one is effective)
myApp.factory('Data', function () {
var data = {
search: ''
};
return {
getSearch: function () {
return data.search;
},
setSearch: function (search) {
data.search= firstName;
}
};
});
myApp.controller('FirstCtrl', function ($scope, Data) {
$scope.firstName = '';
$scope.$watch('search', function (newValue) {
if (newValue) Data.setSearch(newValue);
});
});
myApp.controller('SecondCtrl', function ($scope, Data) {
$scope.$watch(function () { return Data.getSearch(); }, function (newValue) {
if (newValue) $scope.search = newValue;
});
});

Related

Parent scope not updating from select with ng-change from directive

I've seen a couple of articles on this but still can't figure it out.
I am unable to update the parent scope from the within a directive. I have read the articles saying the scope value should not be primitive and instead it should be an object but still can't figure out why this is not working.
angular.module('moduleMihai').controller('someController',
['$scope', '$http', function ($scope, $http) {
$scope.durations = [{
field: 'yearly',
title: 'Yearly'
}, {
field: 'monthly',
title: 'Monthly'
}, {
field: 'weekly',
title: 'Weekly'
}];
$scope.selectedDuration = $scope.durations[0];
$scope.handleDurationSelection = function () {
console.log($scope.selectedDuration.field + ' selected');
$scope.someData.title[0] = "SOMETHING ELSE!!";
};
$scope.someData= {
title: ['Value1', 'Value2', 'Value3'] };
}]);
the directive doesn't have any stuff in it:
angular.module("awaCommon").directive("durationSelection", [
function () {
return {
scope: {}, // tried removing this as well as seen in some articles
restrict: "E",
templateUrl: "duration-selection.html",
link: function ($scope, $element, $attr) {
}
}
}
]);
below the duration-selection.html which contains the select:
<div ng-controller="someController">
<div>
Child: {{someData.title[0]}}
<select
ng-options="item.title for item in durations"
ng-model="selectedDuration"
ng-change="handleDurationSelection()">
</select>
</div>
So this value above in the Child: {{someData.title[0]}} - gets updated properly when value is selected. But the one in here - Parent: {{someData.title[0]}}, in the main route is not:
<div ng-controller="someController">
<div>
Parent: {{someData.title[0]}}
<duration-selection></duration-selection>
</div>
I need the parent scope to be updated in order to update different directives
The way to interact and update your parent scope from your directive is to use
event handling (emit and broadcast) Todd about events $emit and $broadcast : so here we alert the parent when there is a change from the child directive, then the parent listens for the event. I suggest minimal usage due to some bad sides
directive attribute to pass the function: we pass our function to be processed to our directive to handle or call it when needed from the directive ( for me the best method)
inside the directive to update the $scope.$parent.lngBusinessUnit, no need to pass the function to the directive again, not necessary. since the directive is the one handling the logic. we just directly update the parent straight up.
the use of $watch on the parent directive to help check for changes of the selectedDuration $watch read more: this is quite easy since we map the ngModel to the passed param of our directive using two way binding in our return->scope "=" from directive setup
Example For each of the above possibilities
Event Handling
angular.module("eventTest", [])
.controller("mainCtrl", function ($scope){
console.log("am here");
$scope.parentValue = "test";
$scope.valueToPass = ["Male", "Female"];
//let's catch the updated content
$scope.$on('childUpdated', function(event, value){
$scope.parentValue = value;
console.log("updated from child directive", value);
});
})
.directive("child", function(){
return {
restrict:'E',
scope: {
valueToPass:"="
},
templateUrl:"child.html",
controller: function ($scope){
//this is method is triggered when the select of our valueToPass is changed
$scope.childChanges = function (value){
$scope.$emit('childUpdated', value);
console.log("child emitted this:", value);
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="eventTest">
<div ng-controller="mainCtrl">
<h1>Event Test Just for your case, advise you read up</h1>
Parent: <b>{{parentValue}}</b>
<br>
<child value-to-pass="valueToPass"></child>
</div>
<script type='text/ng-template' id="child.html">
Child value : <b>{{menu}}<b> <br>
<select ng-model="menu" ng-change="childChanges(menu)">
<option ng-repeat="item in valueToPass">{{item}}</option>
</select>
</script>
</body>
directive attribute , using function
angular.module("eventTest", [])
.controller("mainCtrl", function ($scope){
console.log("am here");
$scope.parentValue = "test";
$scope.primaryVariable = "Male";
$scope.onChange = function (){
$scope.parentValue = $scope.primaryVariable;
}
})
.directive("child", function(){
return {
restrict:'E',
scope: {
primaryVariable:"=",
callMe:"&"//note this syntax, check angular directive doc
},
templateUrl:"child.html",
controller: function ($scope){
$scope.valueToPass = ["Male", "Female"];
//this is method is triggered when the select of our primaryVarible is changed
$scope.childChanges = function (){
$scope.callMe();
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="eventTest">
<div ng-controller="mainCtrl">
<h1>Directive Function Passing</h1>
Parent: <b>{{parentValue}}</b>
<br>
<child primary-variable="primaryVariable" call-me="onChange()"></child>
</div>
<script type='text/ng-template' id="child.html">
Child value : <b>{{primaryVariable}}<b> <br>
<select ng-model="primaryVariable" ng-change="childChanges()">
<option ng-repeat="item in valueToPass">{{item}}</option>
</select>
</script>
</body>
using scope.$parent
angular.module("eventTest", [])
.controller("mainCtrl", function ($scope){
console.log("am here");
$scope.parentValue = "test";
$scope.primaryVariable = "Male";
})
.directive("child", function(){
return {
restrict:'E',
scope: {
primaryVariable:"="
},
templateUrl:"child.html",
controller: function ($scope){
$scope.valueToPass = ["Male", "Female"];
//this is method is triggered when the select of our primaryVarible is changed
$scope.childChanges = function (){
$scope.$parent.parentValue = $scope.primaryVariable;
}
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="eventTest">
<div ng-controller="mainCtrl">
<h1>Using $parent</h1>
Parent: <b>{{parentValue}}</b>
<br>
<child primary-variable="primaryVariable"></child>
</div>
<script type='text/ng-template' id="child.html">
Child value : <b>{{primaryVariable}}<b> <br>
<select ng-model="primaryVariable" ng-change="childChanges()">
<option ng-repeat="item in valueToPass">{{item}}</option>
</select>
</script>
</body>
Using the $watch
angular.module("eventTest", [])
.controller("mainCtrl", function ($scope){
console.log("am here");
$scope.parentValue = "test";
$scope.primaryVariable = "Male";
$scope.$watch('primaryVariable', function(){
$scope.parentValue = $scope.primaryVariable;
});
})
.directive("child", function(){
return {
restrict:'E',
scope: {
primaryVariable:"="
},
templateUrl:"child.html",
controller: function ($scope){
$scope.valueToPass = ["Male", "Female"];
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="eventTest">
<div ng-controller="mainCtrl">
<h1>using $watch</h1>
Parent: <b>{{parentValue}}</b>
<br>
<child primary-variable="primaryVariable"></child>
</div>
<script type='text/ng-template' id="child.html">
Child value : <b>{{primaryVariable}}<b> <br>
<select ng-model="primaryVariable" ng-change="childChanges()">
<option ng-repeat="item in valueToPass">{{item}}</option>
</select>
</script>
</body>
Hope this helps

How to update model in ui-codemirror

I have two separate controllers which shared a property. If the first controller changes the property the second controller should recognize it and should change the text in the codemirror text area. I tried to figure it out in this fiddle example but I could not find a solution.
var app = angular.module('myApp', ['ui.codemirror']);
app.service('sharedProperties', function() {
var objectValue = {
data: 'test object value'
};
return {
setText: function(value) {
objectValue.data = value;
},
getText: function() {
return objectValue;
}
}
});
app.controller('myController1', function($scope, $timeout, sharedProperties) {
$scope.setText = function(text){
sharedProperties.setText(text);
console.log(sharedProperties.getText().data);
}
});
app.controller('myController2', function($scope, sharedProperties) {
$scope.editorOptions = {
lineWrapping: true,
lineNumbers: true,
readOnly: 'nocursor',
mode: 'xml'
};
$scope.mappingFile = sharedProperties.getText();
console.log($scope.mappingFile);
});
<div ng-app="myApp">
<div ng-controller="myController1">
<input type="text" ng-model="newText"></input>
<button ng-click="setText(newText)">Set Text</button><br/>
</div>
<div ng-controller="myController2">
<ui-codemirror ui-codemirror-opts="editorOptions" ng-model="mappingFile.data" ui-refresh="true"></ui-codemirror>
</div>
</div>
At first, the way that you're doing you have 2 controllers in the same page but without any relation, I'd suggest you to make one of them as child of another.
So, to achieve what you want you need do a kind of watch on that variable from the parent controller.
Steps:
Use the $broadcast to send data to the child controller
$scope.$broadcast('newText', $scope.newText);
Use $on to receive the data from the parent controller:
$scope.$on('newText', function(event, text) {
...
});
Here's the code working based on your original code:
(function() {
'use strict';
angular
.module('myApp', ['ui.codemirror'])
.controller('myController1', myController1)
.controller('myController2', myController2);
myController1.$inject = ['$scope', '$timeout'];
function myController1($scope, $timeout) {
$scope.setText = function(text) {
console.log('Sent...', $scope.newText);
$scope.$broadcast('newText', $scope.newText);
}
}
myController2.$inject = ['$scope'];
function myController2($scope) {
$scope.editorOptions = {
lineWrapping: true,
lineNumbers: true,
readOnly: 'nocursor',
mode: 'xml'
};
$scope.$on('newText', function(event, text) {
if (!text) return;
$scope.mappingFile = text;
console.log('Received... ', $scope.mappingFile);
});
}
})();
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.17.0/codemirror.min.js"></script>
<script src="https://rawgit.com/angular-ui/ui-codemirror/master/src/ui-codemirror.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<div ng-app="myApp">
<div ng-controller="myController1">
<input type="text" ng-model="newText">
<button ng-click="setText()">Set Text</button>
<hr>
<div ng-controller="myController2">
<textarea ui-codemirror-opts="editorOptions" ng-model="mappingFile"></textarea>
</div>
</div>
</div>
</body>
</html>
Some notes:
You don't need to pass ngModel as parameter in your ngClick, you can access it directly in your controller simply calling $scope.newText (as I did);
<input> is a self-closing tag, so of course, you don't need to close it.
I hope it helps.

Passing data from one page to another in angular js

How do I pass data from one page to another in angular js?
I have heard about using something as services but I am not sure how to use it!
Given below is the functionality I want to execute!
On page 1:
<div class="container" ng-controller="mycontrl">
<label for="singleSelect"> Select Date </label><br>
<select nAMe="singleSelect" ng-model="dateSelect">
<option value="2/01/2015">2nd Jan</option>
<option value="3/01/2015">3rd Jan</option>
</select>
<br>
Selected date = {{dateSelect}}
<br/><br/><br/>
<label for="singleSelect"> Select time </label><br>
<select nAMe="singleSelect" ng-model="timeSelect">
<option value="9/10">9AM-10AM</option>
<option value="10/11">10AM-11AM</option>
<option value="11/12">11AM-12PM</option>
<option value="12/13">12PM-1PM</option>
<option value="13/14">1PM-2PM</option>
</select>
<button ng-click="check()">Check!</button>
<br>
Selected Time = {{timeSelect}}
<br/><br/>
User selects time and date and that is used to make call to the db and results are stored in a variable array!
Page 1 controller:
var config= {
params: {
time: times,
date:dates
}
};
$http.get('/era',config).success(function(response) {
console.log("I got the data I requested");
$scope.therapist_list = response;
});
Now how do I send this variable $scope.therapist_list which is an array to next page which will be having a different controller and also if services is use how do define it in my application.js file
application.js:
var firstpage=angular.module('firstpage', []);
var secondpage=angular.module('secondpage', []);
To save the data that you want to transfer to another $scope or saved during the routing, you can use the services (Service). Since the service is a singleton, you can use it to store and share data.
Look at the example of jsfiddle.
var myApp = angular.module("myApp", []);
myApp.controller("ExampleOneController", function($scope, NewsService) {
$scope.news = NewsService.news;
});
myApp.controller("ExampleTwoController", function($scope,NewsService) {
$scope.news = NewsService.news;
});
myApp.service("NewsService", function() {
return {
news: [{theme:"This is one new"}, {theme:"This is two new"}, {theme:"This is three new"}]
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="ExampleOneController">
<h2>
ExampleOneController
</h2>
<div ng-repeat="n in news">
<textarea ng-model="n.theme"></textarea>
</div>
</div>
<div ng-controller="ExampleTwoController">
<h2>
ExampleTwoController
</h2>
<div ng-repeat="n in news">
<div>{{n.theme}}</div>
</div>
</div>
</body>
UPDATED
Showing using variable in different controller jsfiddle.
var myApp = angular.module("myApp", []);
myApp.controller("ExampleOneController", function($scope, NewsService) {
$scope.newVar = {
val: ""
};
NewsService.newVar = $scope.newVar;
$scope.news = NewsService.news;
});
myApp.controller("ExampleTwoController", function($scope, NewsService) {
$scope.anotherVar = NewsService.newVar;
$scope.news = NewsService.news;
});
myApp.service("NewsService", function() {
return {
news: [{
theme: "This is one new"
}, {
theme: "This is two new"
}, {
theme: "This is three new"
}]
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="ExampleOneController">
<h2>
ExampleOneController
</h2>
<div ng-repeat="n in news">
<textarea ng-model="n.theme"></textarea>
</div>
<input ng-model="newVar.val">
</div>
<div ng-controller="ExampleTwoController">
<h2>
ExampleTwoController
</h2>
<div ng-repeat="n in news">
<div>{{n.theme}}</div>
</div>
<pre>newVar from ExampleOneController {{anotherVar.val}}</pre>
</div>
</body>
OK,
you write a another module ewith factory service e.g.
angular
.module('dataApp')
.factory('dataService', factory);
factory.$inject = ['$http', '$rootScope', '$q', '$log'];
function factory($http, $rootScope,$q,$log) {
var service = {
list: getList
};
service.therapist_list = null;
return service;
function getList() {
var config= {
params: {
time: times,
date:dates
}
};
$http.get('/era',config).success(function(response) {
console.log("I got the data I requested");
$scope.therapist_list = response;
});
$log.debug("get Students service");
$http.get('/era',config).then(function successCallback(response) {
service.therapist_list = response.data;
$log.debug(response.data);
}, function errorCallback(response) {
$log.debug("error" + response);
});
}
}
Add this module as dependencies to your both page apps like
var firstpage=angular.module('firstpage', [dataApp]);
var secondpage=angular.module('secondpage', [dataApp]);
and then in your controller consume that service
.controller('homeController', ['$scope', 'dataService', function ($scope, dataService) {
}]);

ng-repeat not updating the list when adding data

my problem is that the ng-repeat is not updating automatically the data. When I press add pin in my code, the element is added correctly to the database. If I reload the page the data appear correctly, but not as angular should.
For the record, the Update and delete are working correctly.
Thanks in advance
This is my app.js code:
var app = angular.module("app", []);
app.controller("AppCtrl", function ($http) {
var app = this;
$http.get("/api/pin").success(function (data) {
app.pins = data.objects;
})
app.addPin = function (scope) {
$http.post("/api/pin", {"title":"new", "image":"http://placekitten.com/200/200/?image=" + app.pins.length})
.success(function(data) {
add.pins.push(data);
})
}
app.deletePin = function (pin) {
$http.delete("/api/pin/" + pin.id).success(function(response) {
app.pins.splice(app.pins.indexOf(pin), 1)
})
}
app.updatePin = function (pin) {
$http.put("/api/pin/" + pin.id, pin);
}
})
This is my index.html file:
<html>
<head>
<title>Pin Clone</title>
<script src="angular/angular.js"></script>
<script src="angular/angular-resource.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="app" ng-controller="AppCtrl as app">
<button ng-click="app.addPin()">Add Pin</button>
<div ng-repeat="pin in app.pins">
<img ng-src="{{ pin.image }}" alt=""/>
<div class="ui">
<input type="text" ng-model="pin.title"/>
<button ng-click="app.updatePin(pin)">Update</button>
<button ng-click="app.deletePin(pin)">Delete</button>
</div>
</div>
</body>
</html>
First of all, you should really use $scope (Doc) in your controller. You can read more about the differences in this post.
Thus your controller would look like this.
app.controller("AppCtrl", ["$scope", "$http",
function ($scope, $http) {
$http.get("/api/pin").success(function (data) {
$scope.pins = data.objects;
});
$scope.addPin = function () {
....
};
$scope.deletePin = function (pin) {
....
};
$scope.updatePin = function (pin) {
....
};
}]);
HTML:
<body ng-app="app" ng-controller="AppCtrl">
<button ng-click="addPin()">Add Pin</button>
<div ng-repeat="pin in pins">
<img ng-src="{{ pin.image }}" alt=""/>
<div class="ui">
<input type="text" ng-model="pin.title"/>
<button ng-click="updatePin(pin)">Update</button>
<button ng-click="deletePin(pin)">Delete</button>
</div>
</div>
</body>
Finally, here comes the core part. You should call $apply (Doc) when your models change. You can read more in this blog post.
$http
.post("/api/pin", {
title: "new",
image:
"http://placekitten.com/200/200/?image="
+ $scope.pins.length
})
.success(function(data) {
$scope.$apply(function() {
$scope.pins.push(data);
});
});
Thus, the full controller code:
app.controller("AppCtrl", ["$scope", "$http",
function ($scope, $http) {
$http.get("/api/pin").success(function (data) {
$scope.pins = data.objects;
});
$scope.addPin = function () {
$http
.post("/api/pin", {
title: "new",
image:
"http://placekitten.com/200/200/?image="
+ $scope.pins.length
})
.success(function(data) {
$scope.$apply(function() {
$scope.pins.push(data);
});
});
};
$scope.deletePin = function (pin) {
$http
.delete("/api/pin/" + pin.id)
.success(function(response) {
$scope.$apply(function() {
$scope.pins.splice(
$scope.pins.indexOf(pin), 1
);
});
});
};
$scope.updatePin = function (pin) {
$http.put("/api/pin/" + pin.id, pin);
};
}]);
Cannot agree with Gavin. First, what you're doing is totally fine. Creating instance of controller is a much better practice than using $scope. Second, $apply() is not needed here.
The problem is ng-repeat created a new scope. While pin is updated, app.pins is not. You should do
var app = angular.module("app", []);
app.controller("AppCtrl", function ($http) {
var app = this;
$http.get("/api/pin").success(function (data) {
app.pins = data.objects;
})
app.addPin = function (scope) {
$http.post("/api/pin", {"title":"new", "image":"http://placekitten.com/200/200/?image=" + app.pins.length})
.success(function(data) {
add.pins.push(data);
})
}
app.deletePin = function (index) {
$http.delete("/api/pin/" + app.pins[index].id).success(function(response) {
app.pins.splice(index, 1)
})
}
app.updatePin = function (index) {
$http.put("/api/pin/" + app.pins[index].id, app.pins[index]);
}
})
and
<html>
<head>
<title>Pin Clone</title>
<script src="angular/angular.js"></script>
<script src="angular/angular-resource.js"></script>
<script src="js/app.js"></script>
</head>
<body ng-app="app" ng-controller="AppCtrl as app">
<button ng-click="app.addPin()">Add Pin</button>
<div ng-repeat="pin in app.pins track by $index">
<img ng-src="{{ pin.image }}" alt=""/>
<div class="ui">
<input type="text" ng-model="pin.title"/>
<button ng-click="app.updatePin($index)">Update</button>
<button ng-click="app.deletePin($index)">Delete</button>
</div>
</div>
</body>
</html>
check here: How to update ng-model on event click using $event in Angularjs
in posted code you've got typo error
app.addPin = function (scope) {
$http.post("/api/pin", {"title":"new", "image":"http://placekitten.com/200/200/?image=" + app.pins.length})
.success(function(data) {
// add.pins.push(data); <--- app not add
app.pins.push(data)
})
}

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