ng-repeat not updating the list when adding data - angularjs

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)
})
}

Related

How to make 2 different controller update and retrieve common data using scope variable and .Service getter setter method in angularjs

I want a angularjs code in which 1 controller is using .service set method to set the value and another controller using the .service get method to retrieve that value.
also i tried this code please let me know why it is not printing the right output.
i tried this code but after setting value it is not printing value...can you help me out in this ..
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js" ></script>
<script>
var app = angular.module('myApp', []);
app.service('sharedProperties', function() {
var stringValue = ' ';
return{
getString: function() {
return stringValue;
},
setString: function(value) {
stringValue = value;
}
}});
app.controller('get', function($scope,sharedProperties) {
$scope.stringValue = sharedProperties.getString();
});
app.controller('set', function($scope, sharedProperties) {
$scope.setString = function(newValue) {
$scope.objectValue.data = newValue;
sharedProperties.setString(newValue);
};
});
</script>
</head>
<body ng-app="myApp">
<div ng-controller="set">
<input type=text ng-model="newValue">
<button onclick="setString(newValue)" >Click here</button>
</div>
<div ng-controller="get">
value is {{stringValue}}
</div>
</body>
</html>
Answers will be appreciated.
I dont understand what is stopping you?
Just read the angular docs https://docs.angularjs.org/guide/services
Quick fiddle
angular.module('serviceApp',[]);
angular.module('serviceApp').service('SharedService',[function(){
var value = '';
this.set = function(val){
value = val;
};
this.get = function(val){
return value;
}
}]);
angular.module('serviceApp').controller('OneCtrl',['$scope','SharedService',function($scope,sharedService){
$scope.form = {value:''}
$scope.setValue = function(){
sharedService.set($scope.form.value);
}
}]);
angular.module('serviceApp').controller('TwoCtrl',['$scope','SharedService',function($scope,sharedService){
$scope.value = sharedService.get();
$scope.getValue = function(){
$scope.value = sharedService.get();
}
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="serviceApp">
<div ng-controller="OneCtrl">
<input ng-model="form.value" type="text" />
<button type="button" ng-click="setValue()">Set</button>
</div>
<div ng-controller="TwoCtrl">
<button type="button" ng-click="getValue()">Get</button>
Value: {{value}}
</div>
</div>

Bind search input to ng-repeat in different controller

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;
});
});

Angular accordion doesn't update UI when data source has been changed

I start learning Angular and faced with some strange behaviour.
I want to add a new header to accordion dynamically but I accordion doesn't reflect it on UI till I explicitly click on some of his items. By some reason he doesn't react on items changes before it starts load itserlf aggain durnig DOM rendering.
var mainApp = angular.module('ui.bootstrap.demo', ['ui.bootstrap', 'ngResource']);
mainApp.factory('teamSharedObj',['$rootScope', function($rootScope) {
return {
teams: [],
peopleInTeam: [],
addNewTeam: function(item) {
console.log("add new team: " + item);
this.teams.push(item);
$rootScope.$broadcast('team.new');
},
addTeamMembers: function(team, teamMembers) {
for (var i = 0; i < teamMembers.length; i++) {
var temp;
// put in team as key-value pair
temp[team] = teamMembers[i]
console.log("add new team member: " + temp);
peopleInTeam.push(temp);
}
if (teamMembers.length != 0) {
$rootScope.$broadcast('teamMember.new');
}
}
}
}]);
mainApp.directive("addNewTeam", ['teamSharedObj', 'teamSharedObj', function (teamSharedObj) {
return {
restrict: 'A',
link: function( scope, element, attrs ) {
element.bind('click', function() {
console.log(scope.teamName)
teamSharedObj.addNewTeam(scope.teamName)
});
}
}
}])
mainApp.controller('teamListCtrl', ['$scope', 'teamSharedObj', function($scope, teamSharedObj) {
$scope.$on('team.new', function(event) {
console.log('new team ' + event);
$scope.items = teamSharedObj.teams;
}
);
$scope.oneAtATime = true;
$scope.items = ['new', 'another one'];//teamSharedObj.teams;
}]);
<!DOCTYPE html>
<html>
<head lang="en">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.js"></script>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-resource.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.2.js"></script>
<script src="js/test.team.js"></script>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body ng-app="ui.bootstrap.demo">
<div id="teamBlock">
<input type="text" ng-model="teamName" >
<input add-new-team type="submit" value="Add new team" >
<!--<button add-book-button>Add data</button>-->
</div>
<div>
{{teamName}}
</div>
<div ng-controller="teamListCtrl">
<accordion close-others="oneAtATime" >
<accordion-group heading="{{d}}" ng-repeat="d in items">
This content is straight in the template.
</accordion-group>
</accordion>
<div ng-repeat="item in items">{{item}}</div>
</div>
</body>
</html>
Can you suggest me please a right way to notifu component about changes in its datasource?
bind is jqLite/jQuery method and does not automatically trigger the digest loop for you. This means no dirty checking will take place and the UI will not be updated to reflect the model changes.
To trigger it manually wrap the code in a call to $apply:
element.bind('click', function() {
scope.$apply(function () {
teamSharedObj.addNewTeam(scope.teamName);
});
});
And since teamSharedObj contains a reference to the array the controller can reference it directly. Then you do not need to use $broadcast:
addNewTeam: function(item) {
this.teams.push(item);
},
And:
mainApp.controller('teamListCtrl', ['$scope', 'teamSharedObj',
function($scope, teamSharedObj) {
$scope.oneAtATime = true;
$scope.items = teamSharedObj.teams;
}
]);
Demo: http://plnkr.co/edit/ZzZN7wlT10MD0rneYUBM?p=preview

ng-hide /ng-show do not work after the model is updated

I have the following
var model =
{
UserInfo :null ,
PlatformID : 1
}
var myApp = angular.module("myApp", []);
myApp.controller("UCtrl",['$scope','$http','$window', function ($scope, $http,$window) {
$scope.Info =model ;
$scope.SearchUser = function() {
$http({
method:"POST",
url : '/FindUser',
data: {UserID : 9999}
}).success(function(data){
$scope.Info.UserInfo = data;
});
};
});
<div ng-hide="{{Info.UserInfo === null}}" >
</div>
When a user is searched for , the Info.User is updated via $http post via
$scope.Info.User = data ;
The ng-hide part does not show after the data is assigned to the Info.User object even though there is data.
Don't user {{}} inside ng-if. Expression will be executed anyway:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.js"></script>
</head>
<body ng-app="Example">
<div data-ng-controller="Cntrl">
<div ng-hide="UserInfo === null" >
User info
</div>
<button data-ng-click="toggle()">Toggle</button>
</div>
<script>
var app = angular.module("Example", [])
.controller("Cntrl", function ($scope) {
$scope.UserInfo = null;
$scope.toggle = function () {
if ($scope.UserInfo === null) {
$scope.UserInfo = 'some value';
} else {
$scope.UserInfo = null;
}
};
});
</script>
</body>
</html>
EDIT: here is another fiddle with code more like yours: http://jsfiddle.net/kpLe544u/3/
I think the issue is that you haven't declared a controller in your HTML so you cannot access the variable Info.UserInfo from that div.
Excerpts from my fiddle: (http://jsfiddle.net/kpLe544u/2/)
HTML
<div ng-app>
<div ng-controller="MyCtrl">
<div ng-show="Info.User">data here</div>
<div ng-show="Info.Test">this won't show</div>
</div>
</div>
controller.js
function MyCtrl($scope) {
$scope.Info = {};
$scope.Info.User = "blah blah";
$scope.Info.Test = null;
}

How to show message for a certain time in angularjs

I'm displaying a message when the user clicks on the button.
I want to show this message for 10 seconds and then hide it.
My code is the following:
<script>
function Ctrl($scope, $window) {
$scope.greeting = 'Hello, World!';
$scope.doGreeting = function() {
$scope.msg="hi";
};
}
</script>
<div ng-controller="Ctrl">
<input type="text" ng-model="greeting" />
<button ng-click="doGreeting()">click</button>
{{msg}}
</div>
You can set a variable that determines whether to show the message or not and hide it and after 10,000 seconds. You will have to inject $timeout as shown below. Then in your view you will need to wrap {{msg}} in a span in order to use ng-show
<script>
function Ctrl($scope, $window, $timeout) {
$scope.greeting = 'Hello, World!';
$scope.showGreeting = false;
$scope.doGreeting = function() {
$scope.msg="hi";
$scope.showGreeting = true;
$timeout(function(){
$scope.showGreeting = false;
}, 10000);
};
}
</script>
<div ng-controller="Ctrl">
<input type="text" ng-model="greeting" />
<button ng-click="doGreeting()">click</button>
<span ng-show="showGreeting ">{{msg}}</span>
</div>
The way I did to show a message for a certain time in angularjs was using AngularJS-Toaster library
To use the library follow this steps:
<link href="https://cdnjs.cloudflare.com/ajax/libs/angularjs-toaster/0.4.9/toaster.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js" ></script>
<script src="https://code.angularjs.org/1.2.0/angular-animate.min.js" ></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angularjs-toaster/0.4.9/toaster.min.js"></script>
Add toaster container directive:
<toaster-container></toaster-container>
Prepare the call of toaster method:
// Display an info toast with no title
angular.module('main', ['toaster'])
.controller('myController', function($scope, toaster) {
$scope.pop = function(){
toaster.pop('success', "title", "text");
};
});
Call controller method on button click:
<div ng-controller="myController">
<button ng-click="pop()">Show a Toaster</button>
</div>
Here you can see a Plunker showing many kinds of toasts showing differents messages
Add the $timeout dependency to your controller. Here's a fiddle:
<div ng-app>
<div ng-controller="Ctrl">
<input type="text" ng-model="greeting" />
<button ng-click="doGreeting()">click</button>
<div class="ng-hide" ng-show="showMessage">{{msg}} {{ greeting }}</div>
</div>
</div>
function Ctrl($scope, $window, $timeout) {
var messageTimer = false,
displayDuration = 5000; // milliseconds (5000 ==> 5 seconds)
$scope.showMessage = false;
$scope.msg = "hi";
$scope.doGreeting = function () {
if (messageTimer) {
$timeout.cancel(messageTimer);
}
$scope.showMessage = true;
messageTimer = $timeout(function () {
$scope.showMessage = false;
}, displayDuration);
};
}

Resources