For loop not waiting for winjs promise completion - microsoft-metro

For loop not waiting for winjs promise completion
for (var j = 0; j < magazineResult[0].data.length; j++) {
downRequest[0].data[j].COVER_PAGE_THUMB = parentUrl + eval(JSON.stringify(downRequest[0].data[j].COVER_PAGE_THUMB));
// Create a new download operation.
downloadFile(eval(magazineResult[0].data[j].COVER_PAGE_THUMB),eval(JSON.stringify(magazineResult[0].data[j].COVER_PAGE_THUMB)));
var url = downRequest[0].data[j].COVER_PAGE_THUMB;
var imgPath = downRequest[0].data[j].ISSUE_ID;
var imgExtension = url.substring(url.lastIndexOf('.') + 1);
var fileName = imgPath + "." + imgExtension;
var promise = Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting);
// Assign the completion handler function.
promise.done(function (newFile) {
MagazineDownLoad.downloadFile(url, fileName, j, newFile);
});
}

If you're trying to get MagazineDownLoad.downloadFile to operate asynchronously then you'll have to modify it's definition:
// in MagazineDownload
function downloadFile(url, filename, j, newfile){
return new WinJS.Promise(function (complete, error, progress) {
var returnValue;
//do the stuff that you do and assign something to returnValue
complete(returnValue);
});
}
Then you can use it asynchronously:
for (var j = 0; j < magazineResult[0].data.length; j++) {
downRequest[0].data[j].COVER_PAGE_THUMB = parentUrl + eval(JSON.stringify(downRequest[0].data[j].COVER_PAGE_THUMB));
// Create a new download operation.
downloadFile(eval(magazineResult[0].data[j].COVER_PAGE_THUMB),eval(JSON.stringify(magazineResult[0].data[j].COVER_PAGE_THUMB)));
var url = downRequest[0].data[j].COVER_PAGE_THUMB;
var imgPath = downRequest[0].data[j].ISSUE_ID;
var imgExtension = url.substring(url.lastIndexOf('.') + 1);
var fileName = imgPath + "." + imgExtension;
var promise = Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting);
// Assign the completion handler function.
promise.done(function (newFile) {
MagazineDownLoad.downloadFile(url, fileName, j, newFile).done(function(result){
//do some more stuff with the result
});
});
}

The WinJS.Promise() runs asynchronously and your for-loop runs in sync. What you are experiencing is expected. If you want to queue your actions you should not perform a loop, but rather queue a new action when your done() is called. Something like this:
var index = 0, data = magazineResult[0].data;
function queueDownload() {
// Duplicate all needed logic here from your question
var promise = Windows.Storage.ApplicationData.current.localFolder.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.replaceExisting);
// Assign the completion handler function.
promise.done(function (newFile) {
MagazineDownLoad.downloadFile(url, fileName, j, newFile);
if (index < data.length) {
queueDownload(++index);
}
});
}
queueDownload(index);

Related

Resolving Promise Angular 2

I have the following problem.
In a function I have a promise as a return type. This function is in the class Hierarchy.
updateNodeValues(entity: String, data: {}): Promise<any>{
let jsonBody = JSON.stringify(data);
let url = environment.endpointCore + '/api/' + entity + '/' + data['id'];
return this.http.put(url, jsonBody, this.options)
.toPromise()
.then(response => {
return response;
})
.catch(this.handleError);
}
This function is in class node.
onSubmit(): void{
var currentForm = this.form.value;
var entityName = this.inflection.classify(this.node.type).toLowerCase();
var requiredData = {};
for(var i = 0; i < this.formItems.length; i++){
this.formItems[i].value = currentForm[Object.keys(currentForm)[i]];
}
for(var i=0; i<this.formItems.length; i++){
requiredData[this.globalService.camelize(this.formItems[i].label)] = this.formItems[i].value
}
Promise.resolve(this.hierarchyService.updateNodeValues(entityName, requiredData)).then(response => {
alert(response.ok);
if(response.ok){
this.globalService.showSuccessMessage('Values updated');
this.refreshGui(requiredData);
}
});
this.editMode = false;
}
The problem is that when i try to resolve promise and invoke this.refreshGui(requireddata) nothing is happening. I have read about how the fat arrow is preserving the 'context' of this, and I do not understand why invoking this method is not doing anything, while invoking successMessage produces expected outcome.
The method that I am invoking looks like this, and it is also in the class node.
private refreshGui(data: {}){
this._node.data = data;
this.objectProperties = new Array();
this.nodeChildren = new Array();
for (var property in data) {
var propertyValue = data[property];
if (propertyValue instanceof Array) {
this.nodeChildren.push({label: property, value: "total: ".concat(propertyValue.length.toString())});
} else {
this.objectProperties.push({label: property, value: propertyValue});
}
}
}
The solution that I found to be working was to implement custom event. The problem was that within the async callback resolution, the context of what this is would "get lost". The fat arrow enabled me to invoke class method with this, but the properties within the would be "lost". Because of this reason I have took the logic from the method, and put it in the callback part and set expected and needed results in some variable. This variable was passed to my custom event and set to class variable in the custom event handler appropriately.

JavaScript - Hangman - Logic Issue

I'm trying to get my Hangman game to check if the letter is found in the word, but as of now it's checking if that letter is found in every character of the word. It won't allow me to guess again after the first guess.
setScreen("WelcomeScreen");
//variables
var WordArray = ["apple", "word", "quiz"];
var currentWord = "";
var wrongCounter = 0;
var bodyPartCounter = 0;
var Guess = "";
//Welcome Screen Code
onEvent("letsGoBtn", "click", function () {
setScreen("playingHangmanScreen");
generateWord();
setUpScreenElements();
});
function generateWord() {
currentWord = WordArray[randomNumber(0,2)];
console.log(currentWord);
}
function setUpScreenElements(){
for (var i = 0; i < currentWord.length; i++) {
showElement("letterArea" + [i]);
}
var showCorrectHint = "hintWord" + currentWord;
showElement(showCorrectHint);
console.log(showCorrectHint);
}
//Guessing Code
onEvent("submitBtn", "click", function () {
Guess = getText("guessInputTxt");
console.log("The guess for " + currentWord + " is: " + Guess);
checkGuess();
});
function checkGuess() {
for (var i = 0; i < currentWord.length; i++) {
if (Guess == currentWord.charAt([i])) {
setText("letterArea" + [i], Guess);
console.log("Correctly guessed letter is: " + currentWord.charAt([i]));
}
else {
wrongCounter++;
console.log("wrongCounter for " + currentWord + " is: " + wrongCounter);
if (wrongCounter == currentWord.length) {
bodyPartCounter++;
showElement("wrongGuessImg" + bodyPartCounter);
setText("livesLeftNumber", (6-bodyPartCounter));
}
if (bodyPartCounter === 6) {
setScreen("gameOverScreen");
}
}
}
resetGuessInput();
}
function resetGuessInput () {
setText("guessInputTxt", " ");
Guess = " ";
wrongCounter = 0;
}
//Game Over Screen and Play Again Button
onEvent("playAgainBtn", "click", function () {
hideElement("hintWord" + currentWord);
generateWord();
setUpScreenElements();
setScreen("playingHangmanScreen");
for (var i = 0; i <currentWord.length; i++) {
setText("letterArea" + [i], " ");
}
for (var j = 1; j < 7; j++) {
hideElement("wrongGuessImg" + [j]);
}
bodyPartCounter = 0;
wrongCounter = 0;
setText("livesLeftNumber", "6");
});
//Victory Screen
onEvent("goHomeBtn", "click", function() {
setScreen("WelcomeScreen");
});
I've attached the code, as well as, included the link to see the app in action.
Here's a link to the app
Thanks in advance!
The checkGuess function needs to first determine where the letter appears in the word (or not), and then update the board one time, instead of updating it for each character:
function checkGuess() {
var foundAtIndex = -1;
for (var i = 0; i < currentWord.length; i++) {
if (Guess == currentWord.charAt([i])) {
foundAtIndex = i;
break;
}
}
if (foundAtIndex >= 0) {
setText("letterArea" + [foundAtIndex], Guess);
// etc...
Luckily, Javascript provides a nice IndexOf function for strings, so you can remove the loop entirely and condense that first part into:
var foundAtIndex = currentWord.indexOf(Guess);

Not able to retrieve callback parameters

var arr = [1,2,3,4,5,6];
Array.prototype.filter2 = function(){
var fir = arguments[0];
var sec = arguments[1];
alert(fir);
alert(sec);
var arr2 = new Array();
for(var item=0; item<this.length;item++){
alert(this[item]); // 1 section
if(sec.call(this[item],fir)){
arr2.push(this[item]);
}
}
return arr2;
}
function xyz (ele ,x){
alert(x);
alert(ele);
return ele > x;
}
arr.filter2(2,xyz);
Till 1'st its running fine but while passing the argument to the callback... x is being alerted as "undefined" whereas ele = fir
Your answer is simple and straight:
either call your function normally,.. i.e
Array.prototype.filter2 = function(){
var fir = arguments[0];
var sec = arguments[1];
alert(fir);
alert(sec);
var arr2 = new Array();
for(var item=0; item<this.length;item++){
alert(this[item]); // 1 section
if(sec(this[item],fir)){
arr2.push(this[item]);
}
}
return arr2;
}
Or if you still want to stick with javascript .call(), then simply use it like this:
Array.prototype.filter2 = function(){
var fir = arguments[0];
var sec = arguments[1];
alert(fir);
alert(sec);
var arr2 = new Array();
for(var item=0; item<this.length;item++){
alert(this[item]); // 1 section
if(sec.call({},this[item],fir)){
arr2.push(this[item]);
}
}
return arr2;
}
call() and apply() are predefined JavaScript function methods. Both methods can be used to invoke a function, and both methods must have the owner object as first parameter.
You can read more about this by clicking here and find it under heading Invoking a Function with a Function Method

One line coffeescript "return if" iterating an array

This is my code (not working)
return monitor if (monitor.uuid is $scope.selectedMonitor) for monitor in $scope.monitors
I want to return monitor if the if is true and I'm trying to do in one single line. Is it possibile?
You could use the when keyword:
getSelectedMonitor = ->
return monitor for monitor in $scope.monitors when monitor.uuid is $scope.selectedMonitor
This generates the following JS:
var getSelectedMonitor = function() {
var monitor, _i, _len, _ref;
_ref = $scope.monitors;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
monitor = _ref[_i];
if (monitor.uuid === $scope.selectedMonitor) {
return monitor;
}
}
};

Google maps api v2 get polygon coordinate

I am a bit of a beginner at google maps api. I managed to let the user to draw a polygon on the map and then I want to get the coordinates on the drew polygon.
I have used the following segment of code but it gave me the following error Uncaught TypeError: Object [object Object] has no method 'getPath'
this is the code that I used
function startShape() {
initialize();
document.getElementById('lat').disabled = true;
document.getElementById('lng').disabled = true;
var polygon = new GPolygon([],"ff0000", 2, 0.7,"ff0000",0.2);
startDrawing(polygon, "Shape " + (++shapeCounter_), function() {
var cell = this;
var area = polygon.getArea();
cell.innerHTML = (Math.round(area / 10000) / 100) + "km<sup>2</sup>";
});
showcoor(polygon);
}
function startDrawing(poly, name, onUpdate) {
map.addOverlay(poly);
poly.enableDrawing(options);
poly.enableEditing({onEvent: "mouseover"});
poly.disableEditing({onEvent: "mouseout"});
GEvent.addListener(poly, "endline", function() {
//var cells = addFeatureEntry(name, color);
//GEvent.bind(poly, "lineupdated", cells.desc, onUpdate);
GEvent.addListener(poly, "click", function(latlng, index) {
if (typeof index == "number") {
poly.deleteVertex(index);
}
});
});
}
function showcoor (poly) {
GEvent.addListener(poly, "endline", function() {
GEvent.addListener(poly, "click", function() {
var str;
var vertices = this.getPath();
for (var i =0; i < vertices.length; i++) {
var xy = vertices.getAt(i);
str += xy.lat() +"," + xy.lng()+"<br />";
}
alert (str);
});
});
}
There is no getPath method on the GPolygon object. See the GPolygon reference.
Instead, you'll need to use getVertexCount() and getVertex(i).
for (var i = 0, I = this.getVertexCount(); i < I; ++i) {
var xy = this.getVertex(i);
str += xy.lat() + ', ' + xy.lng() + '<br />';
}