I am using Angularjs and trying to update my ui. Currently I am making use of these methods to update the ui quickly, but I am getting a 2 second delay before ui changes after controller has been updated with new data.
$scope.sub("panel.service.updateData", updateEventData.bind(this));
function updateEventData(ngEvent, data) {
var errorMessage = "updateEventData() ";
this.timeout(():void=> {
this.scope.list.myList = [];
this.scope.list.myList = data.data;
});
console.log(errorMessage+data.type);
console.log(this.scope.list.myList);
}
I have also tried:
safeApply() method wrapping around the changes in my controller as
well.
wrapping my data inside another object 'list'
updating the controller with a $watch()
updating the controller with sub/pub
I am currently using a sub/pub mechanism to pass data between controllers and services.
I have a console.log() set up right after the call in the controller to show when it was updated with new data, the controller is updated quickly, but my ui doesnt get the changes for about 2 seconds afterwards.
Any ideas?
Yes, you can force Angular to redraw "right now" by calling controller.$apply(). In your code I believe it would be:
this.timeout(():void=> {
this.scope.list.myList = [];
this.scope.list.myList = data.data;
this.scope.$apply();
});
Related
I'm new to meteor.js. Still getting used to it.
I get how templates update reactively according to the cursor updates on the server, like this:
{{#if waitingforsomething.length}} Something Happened! {{/if}}
This is good to display elements on the page, updating lists and content. Now, my question is: what if I want to call some javascript or fire some event when something gets updated reactively? What would be the right way to do it with meteor.js?
Anything inside Tracker.autorun or template instance this.autorun runs with changes in reactive data sources inside these autoruns.
Reactive data sources are ReactiveVar instances, db queries, Session variables, etc.
Template.myTemplate.onCreated(function() {
// Let's define some reactive data source
this.reactive = new ReactiveVar(0);
// And put it inside this.autorun
this.autorun(() => console.log(this.reactive.get()));
});
Template.myTemplate.events({
// Now whenever you click we assign new value
// to our reactive var and this fires
// our console.log
'click'(event, template) {
let inc = template.reactive.get() + 1;
template.reactive.set(inc);
}
});
It is a little bit outdated, but Sacha Greif's Reactivity Basics is a very quick and concise introduction to meteor's reactivity model.
Basically, you have what's called reactive computations, code that observes special data objects (sessions, subscriptions, cursors, etc.) and gets executed whenever any of these reactive sources changes.
This is exposed via the Tracker API
Computation works pretty well for me:
Template.myTemplate.onRendered(function() {
this.computation = Deps.autorun(function () {
if (something) {
$(".reactive").html("Something Happened!");
}
});
});
Template.myTemplate.destroyed = function(){
if (this.computation){
this.computation.stop()
}
};
I Hope this helps.
The usual start to these, I am new to both Ionic and Angularjs. I am developing an Ionic app which at it's heart is very simple. We show a list of classes(sessions), the person clicks on an icon to book the class then the icon changes to allow them to cancel the class. We also update the card to show the number of places remaining in each session on the day.
I have the code working to add and remove a person to and from a class but I am not sure how to update the template view from within the controller.
The controller code is pretty simple
// Check Person in to session.
$scope.addCheckIn = function(schedule){
var promise = sessionDataService.checkinSession(schedule.sessionID);
promise.then(function(data){
// Update (refresh) Schedule Details
// NOT SURE WHAT TO PUT HERE??
});
};
I have tried a number of different approaches including
Refreshing the $state and calling doRefresh and even calling the original controller methods to populate the cards again but the view won't update unless I physically click between states on the screen
//$state.go('app.schedules', {}, {reload: true});
//$scope.doRefresh();
//getScheduleData(formatDate(selectedDate), formatDate(selectedDate), 'true');
I have also looked at $scope.apply and $scope.timeout but I am not sure if this is taking me further from the real solution
What is the correct way to update the view after an update? Should it be after the promise.then in the controller or should I call a service and update everything.
Any tips on what is the best way to do this and a point in the right would be really appreciated.
Thanks everyone.
In your promise, you should add the data to the scope.
$scope.scheduledetails = data;
Then in your template, you will be able to access the object scheduledetails from the controller with AngularJS brackets to bind the data to the HTML.
<h1>{{scheduledetails.title}}</h1>
<p>Details : {{scheduledetails.details}}</p>
AngularJS should take care of refreshing what is needed without having to call any method or anything.
Full example
Controller
$scope.addCheckIn = function(schedule){
var promise = sessionDataService.checkinSession(schedule.sessionID);
promise.then(function(data){
$scope.scheduledetails = data;
});
};
Template
<h1>{{scheduledetails.title}}</h1>
<p>Details : {{scheduledetails.details}}</p>
I have an http request that grabs some data and applies it to a $scope variable:
$http.post("/api/division", 1).success(function(data){
$scope.division = data;
});
Now in my HTML I iterate through that data and display various bits of information, for example:
<div data-ng-repeat="player in division">
<div>{{player.name}}</div>
<div>{{player.number}}</div>
<div>{{player.score}}</div>
</div>
This works great. Now, I have a link that triggers a function to get a new set of data and bind it to the same $scope variable so the frontend will update with new information.
Get Division
$scope.getDivision = function(){
$http.post("/api/division", 2).success(function(data){
$scope.division = data;
});
}
Now, the front end does update with the new information, but there seems to be a lag of 5-10 seconds between the data successfully coming back and the HTML updating. So the problem isn't with the speed of the server. Is it something to do with needing to $emit or $broadcast the change to the variable? How can I get rid of the lag?
I am pretty new to AngularJS and have been working a lot with KnockoutJS bear with me a little as I still haven't quite got my head around when Angular can and cannot track changes.
I am building an app that will have an array of underlying data which initially I will poll and update, but later will improve to push from the server. All data in the app will then just be transforms or filters based on this data. So I have a service to fetch the data and to also fetch the commonly filtered versions of the data like so:
.factory('Scores', function ($resource, Utils, $q, $interval, $filter) {
var scoresResource = $resource('http://localhost:8000/scores'),
scoresData = [];
$interval(function () {
scoresResource.query(function (newScores) {
scoresData.length = 0;
angular.forEach(newScores, function (dataEntry) {
scoresData.push(dataEntry);
});
})
}, Utils.TIMES.SHORT);
return {
getAll: function () {
var deferred = $q.defer();
if (scoresData.length > 0) {
deferred.resolve(scoresData);
} else {
scoresResource.query(function (allScores) {
scoresData.length = 0;
angular.forEach(allScores, function (dataEntry) {
scoresData.push(dataEntry);
});
deferred.resolve(scoresData);
});
}
return deferred.promise;
},
getByLeagueName: function(leagueName) {
return this.getAll().then(function (allScores) {
return $filter('filter')(allScores, function (score) {
return score.League === leagueName;
})
})
}
}
});
And my controller simply fetches the filtered data and adds it to the scope.
.controller('LivescoresCtrl', function ($scope, $stateParams, Leagues, Scores, $interval, Utils) {
Scores.getByLeagueName($stateParams.leagueName).then(function (scores) {
$scope.scores = scores;
});
})
But it seems that the filtered data is not automatically updating when the underlying data updates. I would like to avoid using filters in the view as at times I need to combine data together in ways that I cannot easily achieve.
So I guess my question is why does this not update when the main data updates, and is this a valid approach in an angular world. I could hit the backend for all variations of the data, but as this is a mobile app and all data is needed in the app at all times I don't really want to make extra requests just to combine or filter the data.
Thanks,
You are only setting the data on the controller once, using the promise returned by "getByLeagueName". A promise only ever resolves once!
I'm not sure what ko.computed really does. But you create a new array inside of getByLeagueName that is in no way linked to the original array, by using the filter inside of the service. The new array doesn't "know where it came from"!
It seems you're trying to implement a polling update, which you should do inside the controller, not the service. Think of services as the containers for backend logic, without access to the scope - that's what controllers are for. And as long as you're not working with the scope directly, Angular won't ever update the visible data, because that is the only place that an Angular app gets the displayed data from.
The typical Angular way to use filtered data would be: Make the original data, after fetching it, available on the controller. Then use a filter inside of your view (HTML), i.e.: <div ng-repeat="entry in data | filter: someFilter">. See ng-filter. This way Angular knows when the original data changes, runs the filter on it again, and the UI will update effortlessly.
If you really need to use that filtered data in some other places than the view - and make sure you do - then there's some approaches to that. One is to use the service to notify the controller of data changes: Listen to an event inside the controller via $rootScope.$on, and emit that event in the service via $rootScope.$broadcast.
You can also have a look at this repository, which takes a promise-based approach to polling data, maybe it works well for your task.
I am using angularfire 0.5.0 to set a scope variable called tokenRate in one of my controllers and displaying the value of tokenRate in the corresponding HTML file like so:
Controller:
function TokensCtrl($firebase, $scope) {
$scope.tokenRate = $firebase(new Firebase("https://TEST_URL.firebaseio.com/token_rate"));
}
HTML:
<h1>Token rate is {{ tokenRate }}</h1>
I would expect the value to be displayed the first time and automatically update whenever "token_rate" is changed on the remote firebase. Instead, the tokenRate seems to be undefined initially and does not update when I change "token_rate" on the remote firebase.
The data sync is happening because I am able to receive "change" events from the remote firebase. I am guessing angularjs somehow doesn't know about the object change because putting a $watch on "tokenRate" doesn't trigger anything. I can get it to display the behavior I want by doing:
var value = $firebase(new Firebase("https://TEST_URL.firebaseio.com/token_rate"));
value.$on("change", function() {
$scope.tokenRate = value.$value;
});
But this seems ridiculous to do every time. I don't think I am understanding something here. What is the proper way to set the $scope.tokenRate variable so that it displays the first time and syncs automatically?