Difference between resource.save() with callback and $promise in ngResource using AngularJS - javascript

This is my factory:
// Factory
app.factory('BuildingListService', ['$resource', function($resource) {
return {
selectBuilding: function(building, callback) {
return $resource(window.appSettings.context+'/requests/building')
.save(building, callback);
}
};
}]);
Now, I thought that these two bits of code should behave the same:
First:
$scope.selectBuilding= function(building) {
BuildingListService.selectBuilding(building, function() {
$state.go('requests.detail.analystReview');
});
});
Second:
$scope.selectBuilding= function(building) {
BuildingListService.selectBuilding(building).$promise.then(function() {
$state.go('requests.detail.analystReview');
});
};
However in the first state I get a race condition where the server has not finished the request prior to changing state. I am a little confused as to why that is. The second way I mentioned has no such issue. Is there a reason that the $state.go('requests.detail.analystReview'); would be called in the first bit of code before the server has finished? This one has really confused me.
Also note that solution one is working fine in IE and FireFox, I am starting to suspect a caching issue
Update:
So I have solved my issue, the issue was caching related, IE caches a little aggressively sometimes I should have see that. However I am not sure why the first call would make IE more prone to caching the requests than the second. Thank you to anyone that looked at this.

Might it be that your first example isn't relying on BuildingListService at all? Shouldn't it be something like this?:
$scope.selectBuilding = function(building) {
BuildingListService.selectBuilding(building, function() {
$state.go('requests.detail.analystReview');
});
};

Related

How to use events in NanoGallery2's API

I'm trying to use NanoGallery2 in my web application and it's nearly fantastic, but a couple of glaring omissions from the API (e.g. handling the display of image information) and the idiosyncratic documentation are driving me crazy.
Anyway, the API documentation lists a number of available events and callbacks. I have no trouble using the callbacks to trigger my own functionality, e.g.
$("#nanogallery2").nanogallery2({
items: images,
fnImgDisplayed: onImageDisplayed,
"lightboxNextImage.nanogallery2": onImageDisplayed,
thumbnailHoverEffect2: "scale120|labelSlideUp|toolsAppear",
});
function onImageDisplayed() {
alert("Image Displayed");
}
However, I cannot for the life of me figure out how to trigger my own functionality when any of the events fire. I'm pretty certain that I'm doing it wrong, but no variation I've tried works. I'm particularly interested in the lightboxNextImage and lightboxPreviousImage events. In the documentation all of the event names are listed with a .nanogallery2 suffix (e.g. lightboxNextImage.nanogallery2) so I'm guessing they aren't used in the same way as callbacks but I've tried everything I can think of. Things I've tried unsuccessfully:
$("#nanogallery2").nanogallery2({
items: images,
"lightboxNextImage.nanogallery2": onImageDisplayed,
thumbnailHoverEffect2: "scale120|labelSlideUp|toolsAppear",
});
function onNextImage() {
alert("Next Image")
}
$("#nanogallery2").nanogallery2({
items: images,
lightboxNextImage: onImageDisplayed,
thumbnailHoverEffect2: "scale120|labelSlideUp|toolsAppear",
});
function onNextImage() {
alert("Next Image")
}
$("#nanogallery2").nanogallery2({
items: images,
lightboxNextImage.nanogallery2: onImageDisplayed,
thumbnailHoverEffect2: "scale120|labelSlideUp|toolsAppear",
});
function onNextImage() {
alert("Next Image")
}
That last one even throws up IntelliSense errors because of the period in the key name, but I was getting desperate.
Can anyone put me out my misery? I've made a Codepen here in which I've been trying my various fruitless methods.
As I suspected, I was being completely stupid and this issue only arose because it's midnight and I'm tired. For the benefit of any other tired soul finding their way here, the solution is to add an event listener to the code like this:
$("#nanogallery2").on("lightboxNextImage.nanogallery2", function () {
alert("Next Image");
});
This uses jQuery but since NanoGallery2 is a jQuery plugin that shouldn't be a problem. I've created an updated Codepen with the working solution here.
This came to me 30 seconds after posting the question. Always the way, isn't it?

how to handle JSON file loading with Angular

I have a few controllers that call the method getData() from a service.
In order to not do extra http calls for the same json file, i'm using something like this:
QuizApp.service('quizService', ['$http', function($http) {
var quizService = {},
quizData;
quizService.getData = function() {
return quizData ? quizData : quizData = $http.get('quiz.json');
};
return quizService;
}]);
...but things don't work properly if I do it like that (the data is used to populate a slider and a thumbnail gallery with angular-slick and some problems arise. For now it maybe doesn't matter, I just want to know if the code above makes sense).
On the other hand, if I write getData() like this:
QuizApp.service('quizService', ['$http', function($http) {
var quizService = {},
quizData;
quizService.getData = function() {
quizData = $http.get('quiz.json');
return quizData;
};
return quizService;
}]);
... which will do various http requests for the same json file (doesn't look like a good practice to me), everything works fine and the slick angular gallery works properly. But not 100% of the times though: kind of randomly things don't work well too (same symptoms. I might describe them but again, I don't think that's the point here)
So, in general, regardless of the context, which one of those versions of getData() looks good and which doesn't and why?
UPDATE
As Mark pointed out, Angular has a built in cache, but it's set to false by default. Here is a post and here is the documentation.
If I cache the result of the http request though I get the same problem (I'm not describing it here) I was getting with my second option, and it has apparently nothing to do with that.
Actually, it seems that if I repeat the http request two times (as in my second snippet of code) things work by chance (90% of the time?).
So, by caching the result, at least I get a consistent result, which means in this case that the slick-angular thing won't work properly (never) and I have to look for a solution somewhere else.
Angular $http has a built in cache, which you could make use of here. You can cache all $http requests, which is probably a bad idea, or specific ones.
On a very simple level, this should work for you
quizService.getData = function() {
return $http.get('quiz.json', {cache: true}).then(quizData => {
return quizData;
});
};
You can find out more in the Angular docs for $http

AJAX code insert not firing *sometimes*

I'm trying to modify an ajax callback without actually having access to the original code (don't ask...), and I had found a similar version of the below code on Stack Overflow, which I thought worked great! I put it onto my site, tested it in all browsers, even tested on mobile with success.
So I deployed it this week and, lo and behold, I discovered that for somewhere between a quarter and a third of users this isn't firing correctly. I've been trying like hell to replicate the problem, but again, all of my testing has been successful.
My analytics have told me that the problem is existing for IE, Firefox, and Chrome, and the most up-to-date versions of each, with no tendency toward one browser or another. And from the nature of the problem, I know that the original ajax callback is functioning correctly; it's just my new extra code that's broken.
The site specific code I've written shouldn't be posted online, and stackoverflow isn't jsLint, so I've just replaced it with "some code" here. Suffice to say, I've pored over it looking for potential errors, but I was wondering if anyone knew of any reason why the below code would not work in some but not all cases. Because the below is the only code I'm not sure about.
function init(){
"use strict";
var send = window.XMLHttpRequest.prototype.send,
onReadyStateChange;
function sendReplacement(data) {
if(this.onreadystatechange) {
this._onreadystatechange = this.onreadystatechange;
}
this.onreadystatechange = onReadyStateChangeReplacement;
return send.apply(this, arguments);
}
function onReadyStateChangeReplacement() {
if(this._onreadystatechange) {
var end = this._onreadystatechange.apply(this, arguments);
}
some code
if (this._onreadystatechange){return end}
}
window.XMLHttpRequest.prototype.send = sendReplacement;
}

AngularJS : filter with AJAX

I have been working on AngularJS project recently and came over an interesting problem while trying to create a filter which is using data loaded via AJAX request.
First about the problem:
AngularJS filter is a synchronous piece of code (function) that returns a string which is inserted into your DOM. And in most of the cases it works perfectly fine e.g. following filter that capitilizes first letter:
angular.module('myApp.filters', []).filter('capitilize', function() {
return function (word) {
return word.charAt(0).toUpperCase() + word.substr(1);
}
});
And this works great. Now the question is what if I can't return the desired result right away? Say I need to load some data via AJAX request to get the desired result. If I make an AJAX request my return statement will return an empty result before I get my data. So really the question is how do I notify filter to update itself when my data is loaded?
Solution:
It turned out that the solution was right there in front of me, but it took me some time to figure out how the magic is happening. Say I need a filter that retrieves artist's biography based on their name (yeah, a little bit crazy example but it proves the point):
angular.module('myApp.filters', []).filter('biography', function($q, $http) {
var pending = {};
return function (artist) {
if ( !(artist in pending) ) {
pending[artist] = null;
$http.get('http://developer.echonest.com/api/v4/artist/biographies?api_key=FILDTEOIK2HBORODV&name='
+ artist + '&format=json&results=1&start=0&license=cc-by-sa')
.then(function(response){
pending[artist] = response.data.response.biographies[0].text;
});
}
return pending[artist] || '';
}
});
It works, but how? I made a get request, got my result, but how does it force filter to update itself. The key here is the angular's $q (A promise/deferred implementation inspired by Kris Kowal's Q.)
from angular documentation:
$q is integrated with the $rootScope.Scope Scope model observation mechanism in angular, which means faster propagation of resolution or rejection into your models and avoiding unnecessary browser repaints, which would result in flickering UI.
This means that whenever the promise is resolved it causes the update, in fact here is the code from angular:
function done(status, response, headersString, statusText) {
if (cache) {
if (isSuccess(status)) {
cache.put(url, [status, response, parseHeaders(headersString), statusText]);
} else {
// remove promise from the cache
cache.remove(url);
}
}
resolvePromise(response, status, headersString, statusText);
if (!$rootScope.$$phase) $rootScope.$apply();
}
Hope this was helpful for you. Here is the example, keep in mind that the example is making cross domain ajax calls, you will need to disable cross domain policy of your browser:
http://jsfiddle.net/pJuZ9/8/
IMPORTANT: Keep in mind not to overwhelm filter with same ajax request, otherwise you might end up with this:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
thank you for that post, at least I knew I'm not completely wrong. I have a very similar scenario:
1) a simple translate filter
module.filter('translate', ['Localization', function (localization) {
var translateFilter = function (key) {
return localization.get(key) || "[" + key + "]";
};
translateFilter.$stateful = true;
return translateFilter;
}]);
2) a localization service which stores a JS dictionary. That is updated via XHR. That means that there are multiple possible states of the dictionary:
no localization before init => empty
default localization after init => non-empty
user-defined localization after default is loaded => non-empty
My problem was that the filter result wasn't updated (re-rendered) after the XHR call ended, even though a digest was performed. I had to add
translateFilter.$stateful = true;
to make it work. Even changing filter dependency from service to value did not help. Someone might find this helpful, or event better, tell me, what I was doing wrong :-)

Strange behavior from ko.editables

I'm using the ko.editables plugin for knockout, and it doesn't appear to be caching the previous value correctly. Does anyone have experience with this plugin?
If I do something like this:
var item = { Name: ko.observable("initial") };
selectedItem = ko.observable(item);
ko.editable(selectedItem);
selectedItem.beginEdit();
selectedItem().Name("second");
selectedItem.rollback();
What ends up happening is that selectedItem().Name is still "second", even though it should be "initial".
I looked into the source file, but I don't understand enough about the way JavaScript handles variables to know if what I'm seeing is right or wrong.
I set a breakpoint in the following place within ko.editables.js:
result.rollback = function () {
if (inTransaction()) {
result(oldValue); //breakpoint
inTransaction(false);
}
};
What I found was that oldValue had picked up the new value of the observable, even though commit was never called. Everything I've tried looks exactly like the samples. What am I missing?
Update:
I've updated the code sample. My original code does have the ko.editable() line in it, but thank you to Robert.westerland for pointing it out. It still doesn't work with this extra line.
I know this is an old post, but could be useful for others. I think you might need to call "commit" before the "beginEdit", and I also had to include "true" as a second parameter when calling ko.editable.
Your updated code::
var item = { Name: ko.observable("initial") };
selectedItem = ko.observable(item);
ko.editable(selectedItem, true);
selectedItem.commit();
selectedItem.beginEdit();
selectedItem().Name("second");
selectedItem.rollback();

Categories

Resources