Refreshing of observables in AngularJS - angularjs

I'm using AngularJS and can't find way to resolve this Issue:
there is part from my controller:
$scope.$on('showMoreNotifications', function (event) {
$.ajax({
url: '/notifications',
data: {
notificationCount: 30
},
success: function (e) {
$scope.notifications = e.Messages;
}
});
});
and here is html which using this controller:
<div class="widget" id="widget-notifications" ng-controller="NotificationsCtrl">
<span class="title" ng-click="$parent.$broadcast('showMoreNotifications')">#*showMoreNotifications()*#
Notifikace
</span>
<div class="messages">
<div ng-repeat="item in notifications" class="message-item type-{{item.Entity}}" data-id="{{item.AuditLogId}}">
<span class="type"></span>
<div class="description">
<span class="date">{{item.Date}}</span> / {{item.Message}}
</div>
</div>
</div>
</div>
If I click on span class title on top, controller right call to server and receives JSON data. Unfortunately dont refresh html which is associated with it. When I click second time, html refresh data from first request.

Your template is not updating since your are making xhr calls using jQuery. Those calls are considered "outside of AngularJS" world so AngularJS is not aware of them and doesn't know that it should start it automatic refresh cycle.
You would be much better using excellent $http service from AngularJS to make xhr calls. You would write something like:
$http('/notifications', {params : {
notificationCount: 30
}}).success(function (e) {
$scope.notifications = e.Messages;
});
There was a similar question where the answer helps migrating from jQuery's $.ajax to AngularJS $http: https://stackoverflow.com/a/12131912/1418796
Next, something not directly related, but you really don't have to broadcast events to react on the click event. It would be enough to write:
<span class="title" ng-click="myClickHandler()">
#*showMoreNotifications()*#
Notifikace
</span>
and then in your controller:
$scope.myClickHandler = function(){
//call $http here
}

Now I resolved my issue... It needs apply on scope
like this:
$.ajax({
url: Escudo.UrlHelper.baseUrl + 'Widgets/Notifications/GetLastNotifications',
data: {
notificationCount: 30
},
success: function (e) {
$scope.$apply(function () {
$scope.notifications = e.Messages;
});
}
});

Related

Implement 'loading' icon while waiting for server response (AngularJS)

I am pulling data from an API, so that a template is populated with the response values. However, it sometimes takes around 6 seconds to successfully pull the data, at which point the template is blank except for the headings.
Loading...
Position:
Age:
Height:
Club:
Loading finished:
Anthony Lopes
Portugal
Position: Goalkeeper
Age: 26
Height: 184 cm
Club: Olympique Lyonnais
I want to apply a loading icon (a spinny wheel or something) to indicate that it is waiting for a response from the API.
I'm assuming I need to set the loading state and attach it to a variable, and then say ng-if="loadingContent()" or something, and then create a function to show the loading state.
Is that right? If so can flesh out the process a bit more for me?
If not, how do you do it?
Thanks in advance.
You can use the cgbusy directive:
https://github.com/cgross/angular-busy
Include the file in your HTML and add cgBusy as dependency to your app:
angular.module('myApp', ['cgBusy']);
You can setup a loading template and include it in your HTML like this:
<div cg-busy="{promise: myPromise.$promise, message: 'Loading...',backdrop:true}"></div>
You now have to bind $scope.myPromise to your API call (which should return a promise) like:
$scope.myPromise = $http.post("/echo/json/", data).success(function(data, status) {
$scope.hello = data;
});
This way the loading template (which you can edit) will be visibile as long as the API call is busy. You can add this to any API call you want or add an other template for other calls.
You can customize everything easy in the directive, read more on the provided Github page.
Simply just assign a boolean scope variable when your AJAX/HTTP call is completed. In my example, I just use a $timeout of 5 seconds.
JS/Angular:
$scope.isLoaded = false;
$timeout(function() {
$scope.isLoaded = true;
}, 5000)
}
HTML:
<!-- This element is displayed while loading -->
<div ng-if="!isLoaded" id="loading-container">
<div id="loading-inner">
<img src="http://loadinggif.com/images/image-selection/27.gif" />
</div>
<h4>Loading...</h4>
Position: <br/>
Age: <br/>
Height: <br/>
Club:<br/>
</div>
<!-- This element is displayed after loading is complete -->
<div ng-if="isLoaded">
<h4> Loading finished:</h4>
Anthony Lopes<br/>
Portugal<br/>
Position: Goalkeeper<br/>
Age: 26<br/>
Height: 184 cm<br/>
Club: Olympique Lyonnais<br/>
</div>
Honestly, I could spend hours styling the loading screen in the demo, but that's decent enough to get you on your way so that you can understand how it all works.
If you are using Angular's $http function to perform your API calls, you would set the variable like so:
$scope.isLoaded = false;
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
$scope.isLoaded = true;
});
WORKING EXAMPLE
Below approach you can use:
Template Code:
<div>
<div ng-if="isLoading" class="loaderIcon">
</div>
<div ng-if="!isLoading">
<div>
Main Content
</div>
</div>
</div>
Contorller Code:
app.controller('mainCntrl', function($scope, backendService) {
function successCallback(res) {
$scope.isLoading = false;
}
function failureCallback(res) {
$scope.isLoading = false;
}
$scope.fetchData = function() {
$scope.isLoading = true;
backendService.fetchData(successCallback, failureCallback);
}
});
Service Code:
app.service('backendService', function($http) {
this.fetchData = function(successCallback, failureCallback) {
$http.put('url', data).then(function(res) {
successCallback(res);
}, function(res) {
failureCallback(res);
});
};
});

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

$scope.$on only works on first view

I'm new to AngularJS, but have run into a problem with my Ionic app. On one of my views I'm using ng-repeat to show the values from a pouchDB. However, it only works the first time I view it. If I navigate away from the view and then back it is just blank. I believe I have identified the problem to be part of the code in my controller.
My view:
<ion-view title="All">
<ion-content padding="true">
<div class="list" ng-controller="MyController">
<div class="item item-button-right" ng-repeat="name in names">
{{name.name}}
<button class="button button-clear button-assertive" ng-click="addFav(name.name)">
<i class="icon ion-ios-heart-outline"></i>
</button>
</div>
</div>
</ion-content>
</ion-view>
My Controller:
app.controller("MyController", function($scope, $ionicPopup, PouchDBListener) {
$scope.names = [];
$scope.addFav = function(favName) {
$ionicPopup.alert({
title: 'Favorite',
template: favName + ' has been added',
okText: 'OK'
})
}
$scope.$on('add', function(event, name) {
$scope.names.push(name);
});
});
It seems that the $scope.$on is only run on the first view and thereby causing the view to be blank. Being new, I got the above code from a tutorial and therefore don't really have any ideas on what is causing it or how to fix it?
UPDATE:
I have a broadcast in my factory that syncs my DB:
app.factory('PouchDBListener', ['$rootScope', function($rootScope) {
localDB.changes({
continuous: true,
onChange: function(change) {
if (!change.deleted) {
$rootScope.$apply(function() {
localDB.get(change.id, function(err, doc) {
$rootScope.$apply(function() {
if (err) console.log(err);
$rootScope.$broadcast('add', doc);
})
});
})
} else {
$rootScope.$apply(function() {
$rootScope.$broadcast('delete', change.id);
});
}
}
});
return true;
}]);
Do I need a broadcast in my controller as well?
Initially $scope.names = [];
$scope.$on is an event listener, so there should be $scope.$emit or $scope.$broadcast in order to load your array.
So while loading first time some event occurs through $scope.$emit or $scope.$broadcast and it is listened with $scope.$on, so your array gets loaded.
I think its not happening again when your switch views and come back.
please see last comment for explanation
I just altered your plunker
http://embed.plnkr.co/CZuqLzkU0wd0Soskvi2j/preview
Hope this helps !!!!!!

Resources