I am trying to bind a variable to a scope before it moves to the view but my view shows before the variable is bounded. Here is my code.
$scope.getListing = function() {
var deferred = $q.defer();
$scope.$applyAsync(function() {
$rootScope.listingDetails =[];
referralCasesGroupByCaseStatus.getListing($rootScope.userDetails.rows.item(2).value).then(function(data){
$rootScope.listingDetails = data
deferred.resolve($rootScope.listingDetails)
if($rootScope.fromDashboard === false) {
$scope.showCaseStatus(1);
$state.go('app.case_status')
}
else {
$scope.showCaseStatus($rootScope.statusNumber)
$state.go('app.case_status')
$ionicLoading.hide();
}
});
})
return deferred.promise;
};
var changedNumber = 0;
$scope.showCaseStatus = function(number) {
var finishedPushingListings = false;
$rootScope.listingByCaseStatus = [];
$rootScope.caseStatusListings = [];
if(changedNumber !== 0 && changedNumber !== number) {
changedNumber = number;
}
else {
if(changedNumber > 0) {
$scope.$applyAsync($rootScope.detailsPresent = true);
}
}
$scope.$applyAsync(function() {
angular.forEach($rootScope.listingDetails, function(value, key) {
if(value.real_estate_agent_assignment_status_id == number) {
$rootScope.listingByCaseStatus.push(value);
}
});
})
$scope.$applyAsync(function() {
if($rootScope.listingByCaseStatus == 0 || $rootScope.listingByCaseStatus == undefined || $rootScope.listingByCaseStatus == null) {
$rootScope.detailsPresent = true;
$rootScope.changeNumber = true;
finishedPushingListings = true;
}
else {
$rootScope.detailsPresent = false;
$scope.noMoreItemsAvailable = false;
$rootScope.changeNumber = true;
finishedPushingListings = true;
}
})
};
The main problem here is that the function $scope.showCaseStatus($rootScope.statusNumber) doesnt finish executing before it executes the $state.go('app.case_status') and i would like for it to wait and finish executing before it jumps to the $state.go('app.case_status').
Any help is appreciated.
Since you are using $applyAsync(), the function effects are asynchronous. One way to achieve what you want is to make showCaseStatus() return a promise - and take into account that there are 2 asynchronous blocks:
$scope.showCaseStatus = function(number) {
var ..., d1, d2;
...
d1 = $q.defer();
$scope.$applyAsync(function() {
angular.forEach($rootScope.listingDetails, function(value, key) {
...
});
d1.resolve();
})
d2 = $q.defer();
$scope.$applyAsync(function() {
...
d2.resolve();
})
// both promises must be resolved to continue
return $q.all([d1.promise, d2.promise]);
};
Then the caller becomes:
$scope.showCaseStatus($rootScope.statusNumber).then(function() {
$state.go('app.case_status')
$ionicLoading.hide();
});
Some notes:
If you do not need the async blocks, you can remove them and simplify the code
If the second async block relies on the result of the first, they too should be synchronized
Related
I have a variable called
let idStatus = '';
I need my getValues function to return true and am using this variable to determine whether it returns true or false.
function getValues(){
let idStatus = '';
let getValuesUrl = 'https://something.something.com/v1.0/something/1?apiKey=1234abcdefghijklmnop';
const getValuesRequest = new XMLHttpRequest();
getValuesRequest.responseType = 'json';
getValuesRequest.open('GET', getOptionValuesUrl);
getValuesRequest.send();
getValuesRequest.onreadystatechange = function () {
const response = getValuesRequest.response;
if (response) {
if (getValuesRequest.status == 200) {
console.log('Success');
if(validateIds(response)){
console.log('ID is Valid');
idStatus = true;
}
else {
console.log('ID is NOT Valid');
idStatus = false;
}
}
}
console.log(idStatus);
return idStatus;
}
function validateIds(obj) {
const data = obj['data'];
console.log(data);
let validId = '';
for (let i = 0; i < data.length; i++) {
if (data[i].id == 1) {
validId = true;
}
else {
validId = false;
}
}
console.log(validId);
return validId;
}
Valid IDs runs the way it should and getValues console.logs the appropriate responses when it is true or false, yet idStatus always returns null.
Here I've made a simpler version of your code. I used axios instead of XMLHttpRequest as it's simpler to use.
const axios = require("axios");
async function getValues(link) {
const response = await axios.get(link);
if (!response.statusCode == 200) return false;
if (response.data.some(elm => elm.id != 1)) return false;
return true;
}
// if the status isn't 200, return false;
if (!response.statusCode == 200) return false;
// if one id isn't 1, return false;
if (response.data.some(elm => elm.id != 1)) return false;
If you want more details on Array.some(), here's a link Array.Some()
I have created a Javascript function to make SignalR even more magical:
//Initializable
function Initializable(params) {
this.initialize = function (key, def, private) {
if (def !== undefined) {
(!!private ? params : this)[key] = (params[key] !== undefined) ? params[key] : def;
}
};
}
/*SignalR Updater*/
function SignalRUpdater(params) {
Initializable.call(this, params);
var self = this;
this.initialize("RawHubs", [], true);
this.initialize("RawGroups", {}, true);
this.initialize("Connection", $.connection, true);
this.initialize("Extend", {});
this.Hubs = {};
this.addHub = function (name, extend) {
if (self.Hubs[name]) {
return false;
}
self.Hubs[name] = params.Connection[name];
self.Hubs[name].Groups = {};
params.RawHubs.push(name);
if (!params.RawGroups[name]) {
params.RawGroups[name] = [];
}
if (extend) {
if ((!self.Extend) || (!extend.append)) {
self.Extend = extend;
} else {
if (!self.Extend) {
self.Extend = {};
}
if (extend.append) {
for (var extendIndex in extend) {
if (extendIndex !== "append") {
self.Extend = extend[extendIndex];
}
}
} else {
self.Extend = extend;
}
}
$.extend(params.Connection[name].client, self.Extend);
} else if (self.Extend) {
$.extend(params.Connection[name].client, self.Extend);
}
return true;
};
this.removeHub = function (name) {
if (!self.Hubs[name]) {
return false;
}
for (var groupIndex in self.Hubs[name].Groups) {
self.Hubs[name].Groups[groupIndex].unsubscribe();
}
delete self.Hubs[name];
delete params.RawGroups[name];
params.RawHubs.splice(params.RawHubs.indexOf(name), 1);
return true;
};
this.addGroupToHub = function (hubName, groupName) {
if ((self.Hubs[hubName]) && (self.Hubs[hubName].Groups[groupName])) {
return false;
}
self.Hubs[hubName].server.subscribe(groupName);
self.Hubs[hubName].Groups[groupName] = {}; //Here we can hold group-related data
if (params.RawGroups[hubName].indexOf(groupName) < 0) {
params.RawGroups[hubName].push(groupName);
}
return true;
};
this.removeGroupFromHub = function (hubName, groupName) {
if ((!self.Hubs[hubName]) || (!self.Hubs[hubName].Groups[groupName])) {
return false;
}
self.Hubs[hubName].server.unsubscribe(groupName);
delete self.Hubs[hubName].Groups[groupName];
if (params.RawGroups[hubName].indexOf(groupName) >= 0) {
params.RawGroups[hubName].splice(params.RawGroups[hubName].indexOf(groupName), 1);
}
return true;
};
for (var hubIndex in params.RawHubs) {
self.addHub(params.RawHubs[hubIndex]);
}
params.Connection.hub.start().done(function () {
for (var hubIndex in params.RawGroups) {
for (var groupIndex in params.RawGroups[hubIndex]) {
self.addGroupToHub(hubIndex, params.RawGroups[hubIndex][groupIndex]);
}
}
});
}
I am using it like this, for example:
function statusUpdate(status) {
alert(status);
}
var signalRUpdater = new SignalRUpdater({
RawHubs: ["statusUpdates"],
Extend: {
statusUpdate: statusUpdate
}
});
So far, so good. However, I may have several groups in the same hub and at the point of statusUpdate I do not seem to know about the group. I can send it from server-side as a parameter to statusUpdate, but I wonder whether this is an overkill and whether it is possible out of the box with SignalR.
When sending a group message to clients the server does not send the name of the group the message was sent to. The server selects clients that are members of the group and just sends them the message. If you want to understand the protocol SignalR is using you can find a description I wrote some time ago here.
I have angular filter, when i use it, he always return nothing, but I have a condition suitable values
$scope.seasonIncludes = [];
function changeInputState(event) {
angular.element(event.target).toggleClass('active');
}
$scope.includeSeason = function(season, event) {
$scope.seasonIncludes = []
$scope.seasonIncludes.push(season.season_number);
changeInputState(event)
};
$scope.seasonFilter = function(series) {
if ($scope.seasonIncludes.length > 0) {
if ($.inArray(series.season.season_number, $scope.seasonIncludes) < 0) return;
}
return $scope.series;
};
}]);
I'm trying to work with a plugin which extends jQuery like so:
$.extend({
StatelessDeferred: function () {
var doneList = $.Callbacks("memory"),
promise = {
done: doneList.add,
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function (obj) {
var i,
keys = ['done', 'promise'];
if (obj === undefined) {
obj = promise;
} else {
for (i = 0; i < keys.length; i += 1) {
obj[keys[i]] = promise[keys[i]];
}
}
return obj;
}
},
deferred = promise.promise({});
deferred.resolveWith = doneList.fireWith;
return deferred;
}
});
Problem is (and I'm not even sure it's caused here), after the callback loads, inside a done callback, both this and $(this) are the same, so I end up for example with: this === $(this) === $(document).
I'm not really sure I understand what's being extended. The plugin works fine with it except for the false assignment.
Question:
Could the above extension be causing this === $(this) === $(document)?
EDIT:
Full plugin (120lines):
"use strict";
(function (window, $) {
$.extend({
StatelessDeferred: function () {
var doneList = $.Callbacks("memory"),
promise = {
done: doneList.add,
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function (obj) {
var i,
keys = ['done', 'promise'];
if (obj === undefined) {
obj = promise;
} else {
for (i = 0; i < keys.length; i += 1) {
obj[keys[i]] = promise[keys[i]];
}
}
return obj;
}
},
deferred = promise.promise({});
deferred.resolveWith = doneList.fireWith;
// All done!
return deferred;
}
});
var routes = [],
current_priority = 0,
methods = {
add: function (pattern, priority) {
var i = 0,
inserted = false,
length = routes.length,
dfr = $.StatelessDeferred(),
context = $(this),
escapepattern,
matchingpattern;
if (priority === undefined) {
priority = 0;
}
if (pattern !== undefined) {
// http://simonwillison.net/2006/Jan/20/escape/
escapepattern = pattern.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
matchingpattern = escapepattern
.replace(/<int:\w+>/g, "(\\d+)")
.replace(/<path:\w+>/g, "(.+)")
.replace(/<\w+>/g, "([^/]+)");
while (!inserted) {
if ((i === length) || (priority >= routes[i][2])) {
routes.splice(i, 0, [new RegExp('^' + matchingpattern + '$'), dfr, priority, context]);
inserted = true;
} else {
i += 1;
}
}
}
return dfr.promise();
},
go: function (path, min_priority) {
var dfr = $.Deferred(),
context = $(this),
result;
if (min_priority === undefined) {
min_priority = 0;
}
setTimeout(function () {
var i = 0,
found = false,
slice_index = -1,
slice_priority = -1;
for (i = 0; i < routes.length; i += 1) {
if (slice_priority !== routes[i][2]) {
slice_priority = routes[i][2];
slice_index = i;
}
if (routes[i][2] < min_priority) {
break;
} else if (routes[i][0].test(path)) {
result = routes[i][0].exec(path);
dfr = routes[i][1];
context = routes[i][3];
current_priority = routes[i][2];
found = true;
break;
}
}
if (i === routes.length) {
slice_index = i;
}
if (slice_index > -1) {
routes = routes.slice(slice_index);
}
if (found) {
dfr.resolveWith(
context,
result.slice(1)
);
} else {
dfr.rejectWith(context);
}
});
return dfr.promise();
},
};
$.routereset = function () {
routes = [];
current_priority = 0;
};
$.routepriority = function () {
return current_priority;
};
$.fn.route = function (method) {
var result;
if (methods.hasOwnProperty(method)) {
result = methods[method].apply(
this,
Array.prototype.slice.call(arguments, 1)
);
} else {
$.error('Method ' + method +
' does not exist on jQuery.route');
}
return result;
};
}(window, jQuery));
So I can use this as a router and set a route like so:
$(".element").add("route", "/foo/bar/<path:params>", 2).done(function(params){
// do something, for example
console.log(this);
console.log($(this));
console.log("which will be the same = $('.element'));
});
Hope it's more clear now.
Thanks for having a look.
From the documentation:
If only one argument is supplied to $.extend(), this means the target argument was omitted. In this case, the jQuery object itself is assumed to be the target.
Most cases, jQuery is attached to your document with : $(document).ready()
I think what's happening is jQuery object is wrapped onto the document. Then you merged it with $.extend(myObject). This returns a single object that is both jQuery object and myObject.
I have the following JavaScript function which is used to keep users from inundating our server with Ajax requests:
var validateZip = function () {
var lastSuccessful = parseInt(jQuery('#mailingZip').val(), 10);
return {
validate: function(zip) {
var is5DigitNumber = /^\d{5}$/;
if (is5DigitNumber.test(zip) && lastSuccessful !== zip) {
lastSuccessful = zip;
return true;
} else {
return false;
}
}
}();
This page is reloaded if users input a bad zip code or other errors appear on the form. However since the dom hasn't loaded yet, I always pull NaN from that field.
Placing it in the on document ready for jQuery means that I can't call the function directly.
How can I modify my scope such that the lastSuccessful will remain "private" and get the value once the dom is ready?
function validateZip() { // use function declaration, not function expression
var lastSuccessful = parseInt(jQuery('#mailingZip').val(), 10);
return {
validate: function(zip) {
var is5DigitNumber = /^\d{5}$/;
if (is5DigitNumber.test(zip) && lastSuccessful !== zip) {
lastSuccessful = zip;
return true;
} else {
return false;
}
}
}; // removed premature invocation of function
jQuery(validateZip); // call it on document ready instead
Why can't you call it in ready event? Of course you can enclose it into another function:
$(functon(){
var validateZip = function () {
var lastSuccessful = parseInt(jQuery('#mailingZip').val(), 10);
return {
validate: function(zip) {
var is5DigitNumber = /^\d{5}$/;
if (is5DigitNumber.test(zip) && lastSuccessful !== zip) {
lastSuccessful = zip;
return true;
} else {
return false;
}
}
}();
});
The question is you you need to keep validateZip function as defined global? If you only run it at this point, just omit its declaration and just write:
$(functon(){
(function () {
var lastSuccessful = parseInt(jQuery('#mailingZip').val(), 10);
return {
validate: function(zip) {
var is5DigitNumber = /^\d{5}$/;
if (is5DigitNumber.test(zip) && lastSuccessful !== zip) {
lastSuccessful = zip;
return true;
} else {
return false;
}
}
})();
});
Don't know why I didn't think / do this before. I created a getter/setter on my return function, then on the document ready just called the setter with that value.
var validateZip = function() {
// Track the last sent in zip code -- treat this as private data
var lastSuccessful = "";
return {
validate : function(zip) {
var is5DigitNumber = /^\d{5}$/;
if (is5DigitNumber.test(zip) && lastSuccessful !== zip) {
lastSuccessful = zip;
return true;
} else {
return false;
}
},
setLastSuccessful : function(zip) {
lastSuccessful = zip;
},
getLastSuccessful : function() {
return lastSuccessful;
}
}
}();
jQuery(document).ready( function() {
validateZip.setLastSuccessful(jQuery('#mailingZip').val());
});