Why is angular not rerendering? - angularjs

When I call $scope.remove in the html it calls the rerender function then automatically updates the data in the html.
When I call $scope.post it calls the rerender function and logs the new data. However, it doesn't automatically rerender the html. I have to refresh the page in order to see the up to date data.
I've looked into using $apply but I'm puzzled how it's updating for remove but not post.
Controller:
var updateData = function (resp){
$scope.data = resp.data;
console.log($scope.data);
}
$scope.getEntries = function (){
return $http({
method: 'GET',
url: '/allEntries'
}).then(updateData)
};
$scope.post = function (){
return $http({
method: 'POST',
url: '/newEntry',
data: $scope.entry
}).then(function (resp){
$scope.getEntries();
})
};
$scope.remove = function (opp){
return $http({
method: 'POST',
url: '/deleteEntry',
data: opp
}).then(function (){
$scope.getEntries();
})
}
I'm thinking it might be something to do with having the functions called in different html files but since they both have the same controller I would think that wouldn't be the case.
<html>
<body ng-app = "app">
<div ng-controller = "controller">
<form ng-submit = "post()">
<input type="submit" value="Submit">
</form>
</div>
</body>
</html>`
<html>
<body ng-app = "app">
<div ng-controller = "controller">
<ul>
<li ng-repeat = "job in data" ><input type = "button" ng-click = "remove(opp)" value="Delete"></li>
</ul>
</div>
</body>
</html>`

Indeed, you have two different sections, each with their own controller, and thus each with their own scope:
one which displays the list of items
one which diesn't display anything
You're posting from the section which doesn't display anything, so it refreshes the list in the scope of that section, which still doesn't display anything.
So, in short, both sections don't have the same controller. They have different controller instances, and those instances happen to have the same type. But they're still completely independant from each other.
And actually, re-reading your question, it's actually worse than that. It seems you have two browser tabs or frames opened. You are posting from one of the tabs, and hope that the other one will refresh automatically. That won't happen: the two tabs are completely independant applications.

Related

html data get from $http GET is not showing properly in Angular js..?

I have defined a controller like this :
app.controller("home", function ($scope, $http, $common) {
$http({
method: "GET",
url: '/posts/loadData'
}).then(function (response) {
//console.clear()
if (typeof response.data.posts != 'undefined') {
console.log(response.data.posts);
$scope.posts = $common.arrangePosts(response.data.posts);
}
});
})
and a service to arrange data :
app.service('$common', function ($timeout, $sce, $httpParamSerializerJQLike) {
var that = this;
this.arrangePosts = function (rawPosts) {
var posts = [];
$.each(rawPosts, function (key, value) {
posts.push({
postId: value.postId,
postLink: '/post/' + that.cleanString(value.title) + '/' + value.postId,
title: value.title,
summary: $sce.trustAsHtml(value.summary)
});
});
return posts;
}
});
using values in html like this :
<div class="widget fullwidth post-single">
<h4 class="widget-title">Latest</h4>
<div class="widget-content">
<ul>
<li ng-repeat="post in posts">
<h4 class="list-title">{{post.title}}</h4>
{{post.summary}}
</li>
</ul>
</div>
</div>
Data coming from server in JSON form :
Object { postId="4", title="asdf", summary="<p>asdf</p>"}
but all the html tags are printing on my page as it is (like a text) in summary.
In many SO posts people suggested to use $sce.trustAsHtml but its not working for me. Please suggest anyway to solve my problem.
Any help will be appreciated..!!
have you tried this?
<div ng-bind-html='post.summary'></div>
You could solve this over a directive. Did you know, that you can use JQuery Lite inside AngularJS to manipulate the DOM?
Here a quick example:
angular.module("PostsDirective",[])
.directive("posts", function($sce){
return {
link: function($scope, $element, $attrs){
//the HTML you want to show
var post = "<div>hello world</div>";
var posts = [post,post,post,post];
//iterating through the list (_.each is a function from underscore.js)
_.each(posts, function(element){
//if you want to save the trusted html string in a var you can do this with getTrustedHtml
//see the docs
var safeHtml = $sce.getTrustedHtml($sce.trustAsHtml(element));
//and here you can use JQuery Lite. It appends the html string to the DOM
//$element refers to the directive element in the DOM
$element.append(safeHtml);
});
}
};
});
And the html
<posts></posts>
This also pretty nice for the readability for your HTML code. And you can use it everywhere on your page.
BTW:
As i can see, you get the HTML elements directly from a REST-Service. Why don't you get just the data and insert it into the ng-repeat? If you transfer all the HTML you get a pretty high overhead if you have loads of data.

angular ng-repeat to always show even on empty object

Hi I want to post item to server, and with each successful addition, automatically add it to DOM with ng-repeat
<div class="" ng-repeat="book in books" >
<div id="eachBook">{{book.title}}</div>
</div>
to POST the data and also to upload an image file, I use Jquery ajax, and $state.go(".") to reload the current page:
var fd = new FormData();
fd.append("file", bookImage);
$http({
method: 'POST',
url: "/someurl,
data: fd,
headers: {
'Content-Type': undefined
}
}).success(function(Image){
var book_obj = {
bookTitle: bookTitle,
bookImage: Image._id
};
$http.post("url to owner book", book_obj)
.success(function(data){
$scope.bookImage = data.bookImage;
$timeout(function(){
alert("success", "successfully added your book");
$state.transitionTo('book', {}, { reload: true });
},2000);
})
})
The problem is with first addition, the DOM is still empty, and even though I use $state to reload the page, it still not working for the first addition. In the end I need to refresh the page manually by clicking refresh.
after the first addition, it works fine. With each book added, it automatically added to DOM..
Any idea how to automatically start the first one without manually rendering the page? using $timeout to delay the refresh has no effect.
Is it not just a simple post to list on success?
var app = angular.module('myApp', []);
app.controller('bookCtrl', function($scope, $http, $timeout) {
$scope.init = function(){
$scope.title = 'initial book?'
postBook();
};
$scope.books = [];
$scope.post = function() {
postBook();
};
function postBook(){
if (!$scope.title) return;
// timeout to simulate server post
$timeout(function() {
$scope.books.push({title:$scope.title});
$scope.title = null;
}, 1000);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="bookCtrl" ng-init="init()">
<div class="" ng-repeat="book in books">
<div class="eachBook">{{book.title}}</div>
</div>
<input type="text" ng-model="title" /><button ng-click="post()">save</button>
</div>
EDIT: Not sure why your DOM isn't ready but how about ng-init to accomplish an initial book post?

Angularjs how can I reload the content

I have this code that loads the content when the page load,
Now I want to know how to reload the content by clicking the button.
Can you show me how to do it with example please?
Javascript code:
.controller('InterNewsCtrl', function($scope, NewsService) {
$scope.events = [];
$scope.getData = function() {
NewsService.getAll().then(function (response) {
$scope.events = response;
}), function (error) {
}
};
$scope.getData(); // load initial content.
})
Html code:
<ons-toolbar fixed-style>
<div class="left">
<ons-back-button>Voltar</ons-back-button>
</div>
<div class="right">
<ons-toolbar-button><ons-icon icon="ion-android-refresh"></ons-icon></ons-toolbar-button>
</div>
<div class="center">Internacional</div>
</ons-toolbar>
I think you're asking how to just retrieve new events from the backend. If that's correct, you don't need to reload the entire page.
You already have a function called getData which goes and retrieves you data via your service. Assuming your service doesn't cache the data, just call getData from your button:
<ons-toolbar-button ng-click="getData()"><ons-icon icon="ion-android-refresh"></ons-icon></ons-toolbar-button>
P.S. if you do explicitly have the cache set to true in your service, you can remove the cached data with $cacheFactory.get('$http').removeAll();.
For reloading same page in angular Js without post back
first remove that url from template cache if you call $route.reload() without removing it from $templateCache it will get it from cache and it will not get latest content
Try following code
$scope.getdata=function()
{
var currentPageTemplate = $route.current.templateUrl;
$templateCache.remove(currentPageTemplate);
$route.reload();
}
and Call it as following
<input type="button" ng-click="getdata();" value ="refresh"/>
Hope this will help
Please reffer this

Angular JS - Parent view not updating when scope changes

I'm building a simple Angular test app and have run into a problem. I have a list of items and an "add item" link at the bottom of the list (the list is stored on a simple NodeJS server). This "add item" link loads a child view that lets the user set the name of the new item. When the user clicks done the item is added to the list on the server, then tells the parent list to update. In the console I can see that the data is being passed back to the parent but the view isn't reflecting the new list of items. I've looked into $scope.$apply but as I am never using a third party library I have no reason to use it (I have tried it and it always gives the error "$digest is already running" which seems expected after looking at the docs). Here's the code in question:
HTML Parent List
<ul data-ng-controller="listCntrl">
<li data-ng-repeat="item in items">
{{item.name}}
</li>
<li>Add Item</li>
</ul>
<div data-ui-view></div> <!--Child view loaded here-->
HTML Child View
<div data-ng-controller="newItemCntrl">
<input type="text" data-ng-model="name"></input>
<a data-ng-click="addItem()">Done</a>
</div>
Controllers
app.controller('listCntrl',function($scope, ListFactory){
ListFactory.getItems().success(function(data){
$scope.items = data;
});
$scope.update = function(){
ListFactory.getItems().success(function(data){
console.log(data); //The correct list is in data
$scope.items = data; //This doesn't cause the view to update!
});
}
});
app.controller('newItemCntrl',function($scope){
$scope.addItem = function(){
$http({
method: 'POST',
url: '/addItem',
data: JSON.stringify( {name: $scope.name} ),
headers: {'Content-Type': 'application/json'},
})
.success(function(){
$scope.$parent.update();
});
}
});
Factory
app.factory('ListFactory', function($http){
return {
getItems: function(){
return $http({
method: 'POST',
url: '/getItems',
headers: {'Content-Type': 'application/json'}
});
}
}
});
Everything works on the server side and in the update() function it prints out the updated list, but somehow the $scope.items assignment isn't causing the list view to update. If I refresh the page then the list appears correctly. What am I doing wrong here? I'm guessing it's a problem with my understanding of the $scope.$parent but I can't seem to figure it out. Thanks for you help!
The 'listCntrl' controller is on the element, while the 'newItemCtrl' is bound to a child view of data-ui-view, which is a sibling of the element, not a child.
Thus, the scope created in newItemCtrl does not have the scope created by listCntrl in its parent chain.
Try something like this:
<div data-ng-controller="listCntrl">
<ul>
<li data-ng-repeat="item in items">
{{item.name}}
</li>
<li>Add Item</li>
</ul>
<div data-ui-view></div> <!--Child view loaded here-->
</div>
BTW, you don't actually need to use $scope.$parent in this case. All child scopes (but not isolated scopes) have prototypical inheritance from their parents, i.e. scope.__proto__ === scope.$parent. Just using $scope.update() should suffice, as long as no directive between this scope and the parent scope that defined the update function made an isolated scope.

Refresh data on click outside controller in angular

I am trying to grasp the idea behind angular and ran into my first obstacle involving accessing data from outside the scope (the app?)
Here is a very simple example of what I'm trying to do:
HTML:
<div class=logo>
<a href='/refresh'>Refresh</a>
</div>
<div ng-app ng-controller="threadslist">
<div class='thread_list_header'>
<table class='thread_list_table'>
<tr class='table_header'>
<!--1--><td class='table_c1'></td>
<!--2--><td class='table_c2'>{{name}}</td>
<!--3--><td class='table_c3'>Cliq</td>
<!--4--><td class='table_c4'>Last Poster</td>
<!--5--><td class='table_c5'><a class="clickme">Refresh</a></td>
</tr></table>
</div>
<table class='thread_list_table' >
<tr class="thread_list_row" ng-repeat="user in users">
<!--1--><td class='table_options table_c1'></td>
<!--2--><td class='table_subject table_c2' title="">{{user.subject}}</td>
<!--3--><td class='table_cliq table_c3'></td>
<!--4--><td class='table_last table_c4'><span class="thread_username"><a href=#>{{user.username}}</a></span></td>
<!--5--><td class='table_reply table_c5'><abbr class="thread_timestamp timeago" title=""></abbr></td>
</tr>
</table>
</div>
JS:
function threadslist($scope, $http) {
$scope.name = 'Ricky';
// Initialising the variable.
$scope.users = [];
$http({
url: '/cliqforum/ajax/ang_thread',
method: "POST",
}).success(function (data) {
console.log(data);
$scope.users = data;
});
// Getting the list of users through ajax call.
$('.table_header').on('click', '.clickme', function(){
$http.get('/cliqforum/ajax/ang_thread').success(function(data){
$scope.users = data;
});
});
}
This is the part I can't figure out. My logo is supposed to clear whatever filter is on the current 'user' data. However, it sits outside the scope (and I imagine I shouldn't expand the scope to be the entire page?)
I have read something about scope.$spply but can't quite figure out what I'm supposed to do:
$('.logo').on('click', 'a', function() {
scope.$apply(function () {
$scope.users = data;
});
});
It's not quite necessary that I do it THIS way...I would just like to do what is correct!
Thanks!
and I imagine I shouldn't expand the scope to be the entire page?
Why not? That's definitely the way to do it. Just include the logo into the scope and you can then access it from your application, and use ng-click to add a click handler.
In fact, you should avoid using jQuery click handlers within your application. You could transform your JavaScript like so:
$scope.tableHeaderClick = function() {
$http.get('/cliqforum/ajax/ang_thread').success(function(data){
$scope.users = data;
});
});
Then update the HTML like so:
<tr class='table_header' ng-click="tableHeaderClick()">
it is an angular anti-pattern to include DOM elements in controller. you want to use the ng-click directive to respond to click events
see this plnkr:
http://plnkr.co/edit/KRyvifRYm5SMpbVvWNfc?p=preview

Resources