In Vue router, why would this happen? this$1.pending !== route - javascript

In most cases, when I use this.$router.push() everything works fine. However, there is one case where I'm doing that that throws an exception. The page changes just fine - it is just that the message vue-router.esm.js?8c4f:2007 Uncaught (in promise) appears in the console.
I don't see anything different in the way I call this particular route than any other.
The code below is where it fails in the router. this$1.pending1 and route are both objects. I put a breakpoint there and checked the following: JSON.stringify(this$1.pending) === JSON.stringify(route) and that returns true, so they have identical data.
In javascript, objects are not considered equal unless they are the same, but I don't know why, in this case, the object is a clone instead of being identical.
runQueue(queue, iterator, function () {
var postEnterCbs = [];
var isValid = function () { return this$1.current === route; };
// wait until async components are resolved before
// extracting in-component enter guards
var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
var queue = enterGuards.concat(this$1.router.resolveHooks);
runQueue(queue, iterator, function () {
if (this$1.pending !== route) { // EXCEPTION ON THIS LINE
return abort()
}
this$1.pending = null;
onComplete(route);
if (this$1.router.app) {
this$1.router.app.$nextTick(function () {
postEnterCbs.forEach(function (cb) {
cb();
});
});
}
});
});

This isn't exactly an answer, but here's a discussion of other people who have run into the same thing: https://github.com/vuejs/vue-router/issues/2932
It doesn't sound like there is a resolution, but since it appears harmless, (except for the message in the console), I'm going to not worry about it at the moment.

Related

How do I perform object manipulation on an asynchronous result object?

I was wondering how I can manipulate a JS object from one file, in another, asynchronously.
I don't really have a lot of experience with asynchronous code principles.
Situation:
I have a file, app.js, in which I dynamically create 'app panels' based on my HTML.
$("div.app-panel[data-panel]").each(function() {
// create panel objects for all html divs with class app-panel
var panel = {};
panel.div = $(this);
panel.name = $(this).attr("data-panel");
panel.isActive = ($(this).attr("data-active-panel") == "true" ? true : false);
panel.onActive = () => {
// default functionality to execute when activating an app panel
panel.isActive = true;
$(panel.div).attr("data-active-panel", true);
};
panel.onInactive = () => {
// default functionality to execute when deactivating an app panel
panel.isActive = false;
$(panel.div).attr("data-active-panel", false);
};
app.panels.push(panel);
});
Now I want to be able to override the onActive method in my other file, main.js, but how do I know if this code has finished running?
I can't apply .filter() or .find() on app.panels, it will return undefined.
I can console.log(app.panels), and it will return the array to my console... but I can't do:
panel = app.panels[0]
this will give me undefined.
I tried to create a function inside of object app, which accepts a callback function that will use app.panels as parameter. This however gives me the same results...
Then I tried to solve it this way:
app.getPanels = async () => {
var promise = new Promise(function(resolve, reject) {
resolve(app.panels);
});
return promise;
};
var getPanels = async (callBack) => {
const appPanels = await Promise.all(app.getPanels());
console.log(appPanels);
callBack(appPanels);
}
this raises the error "TypeError: object is not iterable".
Anyhow, I think my code makes it quite clear that I am not familiar with promises at all, what am I doing wrong?
Promisers aren't the solution here. It's all to do with coordination of code loaded from different files.
A typical strategy would be for :
all .js files except "main.js" to contain classes/functions, but not execute anything.
"main.js" to coordinate everything by creating class instances and calling functions/methods.
"main.js" to be loaded last.

Javascript doesn't throw error while trying to call get on an object

I'm trying to implement a service using AngularJS to manage cookies.
angular
.module('myModule')
.service('CookiesService', ['$cookies', function ($cookies) {
var cookies = {
cookie1: {},
cookie2: {}
};
function CookiesService() {
}
CookiesService.prototype.update= function(name, options) {
cookies[name] = options ? options : {};
};
CookiesService.prototype.isCookie = function(name) {
if(!cookies.hasOwnProperty(name)) {
throw 'Unknown cookie name';
}
return cookies.hasOwnProperty(name);
};
function getter(prototype, name, getter) {
Object.defineProperty(prototype, name, {
get:getter,
enumerable: true,
configurable: true,
});
}
Object.keys(cookies).forEach(function(name) {
getter(CookiesService.prototype, name, function() {
try {
CookiesService.prototype.isCookie(name);
return $cookies.get(name);
} catch (e) {
throw new Error('Invalid cookie'); // never thrown!
}
});
/*Setter code*/
return new CookiesService();
});
}
]);
So basically, if I want to retrieve a cookie after setting it, I would simply call CookiesServices.
Howeber, if I try to call the getter to retrieve a cookie that doesn't exist, I expect to get an error in the console. Since I have the throw, but it seems that it is not working and I am not able to debug and see whether the code gets executed at this level or not.
Example: CookiesService.cookie3 <- gives me undefined, no error thrown.
Also assuming that I do as follows:
CookiesService.prototype.isCookie = function(name) {
return cookies.hasOwnProperty(name);
};
Object.keys(cookies).forEach(function(name) {
getter(CookiesService.prototype, name, function() {
if (!CookiesService.prototype.isCookie(name)) {
throw new Error("blabla");
}
return $cookies.get(name);
});
it won't throw the blabla error if I try to call CookiesService.cookie2
First, it might be a good idea to rename your function getter(){} to function createGetter(){}. This will make things easier to understand especially with the last param on said function also named "getter".
Second, you stated:
Howe[v]er, if I try to call the getter to retrieve a cookie that doesn't exist...
This simply will never happen:
Remember your foreach loop is creating getters for existing cookies (the stuff defined under var cookies). There will never be a getter defined on your service object that doesn't also have a corresponding value under cookies; thus doing something like CookiesService.cookie3 isn't calling a getter at all.
If you think about it, how could you expect to exercise code (e.g., get: function(){...}) for a getter that's never been defined anyways?
So calling CookiesService.cookie3 will never execute code that you setup for existing cookies and therefore will never break into your error throws.
What you are seeing with the 'undefined' error is JS literally telling you it's not a function, it's not a getter, it's not a property... it's not anything defined on the object CookiesService.
You can just check for undefined instead of waiting for an error. Yes in javascript you can access an undefined value. As long as you don't try to access a value within the undefined you won't get an error
Object.keys(cookies).forEach(function(name) {
getter(CookiesService.prototype, name, function() {
CookiesService.prototype.isCookie(name);
if ($cookies.get(name) !== undefined) return $cookies.get(name)
else throw new Error('Invalid cookie');
});

Avoiding multiple load of javascript file

I add this snippet to each javascript file used in my asp.net web api application to avoid multiple load :
Fullcalendar.js
blog = {};
blog.comments = blog.comments || {};
blog.comments.debugMode = false;
blog.isFirstLoad = function (namesp, jsFile) {
var isFirst = namesp.jsFile.firstLoad === undefined;
namesp.jsFile.firstLoad = false;
return isFirst;
};
$(document).ready(function () {
if (!blog.isFirstLoad(blog.comments, "fullcalendar.js")) {
return;
}
});
Sometimes I get a weird exception
Uncaught TypeError: Cannot read property 'firstLoad' of undefined
I need to know :
Why this happens?
How can I fix it?
A couple of problems there.
First, you shouldn't be loading the file more than once in the first place, so it shouldn't be necessary to go through this business of trying to figure out whether you've loaded it.
But if you want to do that:
The first practical issue is that you're always doing this:
blog = {};
...which means if there's already a blog global, you're wiping out its value and replacing it with an empty object. If you want to use an existing global's value or create a new one, do this:
var blog = blog || {};
That seems odd, but since repeated var declarations are fine (and don't change the variable), that will use an existing one's value, or if there isn't one (or its value is falsey) it will create a new one and initialize it with {}.
Then, the line
namesp.jsFile.firstLoad = false;
...looks for a property called jsFile on namesp and assumes it's not null or undefined. It doesn't look for a property using the jsFile argument's value.
To do that, use brackets notation:
namesp[jsFile].firstLoad = false;
Even then, though, you're assuming it's not null or undefined, but it may well be. You probably just wanted:
namesp[jsFile] = false;
Or possibly:
namesp[jsFile] = namesp[jsFile] ||{};
namesp[jsFile].firstLoad = false;
That said, it seems really odd to use blog.comments to track whether JavaScript files have been loaded. If the file may have already been loaded, just this will do it:
var fullCalendarLoaded;
if (fullCalendarLoaded) {
// It's already loaded
} else {
// It isn't, but it is now
fullCalendarLoaded = true;
// ...do your init...
}
Or if you have several of these and want to use a single global for it:
var loadedScripts = loadedScripts || {};
if (loadedScripts.fullCalendar) {
// Already loaded
} else {
// Not loaded yet
loadedScripts.fullCalendar = true;
// ...do init...
}
Or if using the filename is important:
var loadedScripts = loadedScripts || {};
function firstLoad(filename) {
if (loadedScripts[filename[) {
return false;
}
// Not loaded yet, remember we've loaded it now
loadedScripts[filename] = true;
return true;
}
Then:
if (firstLoad("fullcalendar.js")) {
// First load, do init...
}
It's fairly straightforward:
On your initial run, you define
blog = {};
blog.comments = blog.comments || {};
blog.comments.debugMode = false;
In theory, this means that on some loads, blog is:
var blog = {
comments: {
debugMode: false
}
}
You then pass blog.comments into your function isFirstLoad as the namesp parameter. In that function, you do the evaluation:
namesp.jsFile.firstLoad === undefined;
Well, you never defined the jsFile property of blog.comments. This means it is undefined. Trying to access the property firstLoad of an undefined variable will give you your error
Uncaught TypeError: Cannot read property 'firstLoad' of undefined

Meteor.js Collection empty on Client

Why is it that myCollection.find().fetch() returns an empty array [] even though the call is made within if(data){...}? Doesn't the if statement ensure that the collection has been retrieved before executing the console.log()?
Template.chart.rendered = function() {
var data = myCollection.find().fetch();
if(data) {
console.log(data);
}
$('#chart').render();
}
This returns [] in the browser Javascript console.
You could use count() instead which returns the number of results. data itself would be an empty array, [] which isn't falsey ( [] == true ).
Also don't use fetch() unless you're going to use the raw data for it because its quite taxing. You can loop through it with .forEach if you need to.
var data = myCollection.find();
if(data.count())
console.log(data);
//If you need it for something/Not sure if this is right but just an example
$('#chart').render(data.fetch())
The problem is that you have to wait for data from the server. When you just use Template.name.rendered function it is immediately invoked. You have to use Template.name.helpers function to wait for data from the server. Everything is described in the documentation.
It seems when you "remove autopublish" you have to also subscribe on the client.
if(Meteor.isClient) {
Meteor.startup(function() {
Myvars = new Mongo.Collection("myvars");
Meteor.subscribe('myvars')
});
}
and enable allow and publish on the server
if(Meteor.isServer) {
Meteor.startup(function () {
Myvars = new Mongo.Collection("myvars");
Myvars.allow({
insert: function () {
return true;
},
update: function () {
return true;
},
remove: function () {
return true;
}
});
if (Myvars.find().count() == 0) {
Myvars.insert({myvalue:'annoyed'});
}
Meteor.publish("myvars", function() {
return Myvars.find();
});
});
}
I'm new to this as well. I was just looking to have a global value that all clients could share. Seems like a useful idea (from a beginner's perspective) and a complete oversight on the Meteor teams behalf, it was nowhere clearly documented in this way. I also still have no idea what allow fetch is, that too is completely unclear in the official documentation.
It does, but in javascript you have the following strange behaviour
if ([]){
console.log('Oops it goes inside the if')
} // and it will output this, nontheless it is counter-intuitive
This happens because JS engine casts Boolean([]) to true. You can how different types are casted to Boolean here.
Check if your array is not empty in the beginning.
a = [];
if (a.length){
//do your thing
}

Variable scope in Javascript Object

I'm discovering the concept of "objects" in JavaScript. I'm making an RSS Parser, and I have an error (commented).
function MyParser (feed_url) { // Construct
"use strict";
this.feedUrl = feed_url;
this.pubArray = [];
if (typeof (this.init_ok) == 'undefined') {
MyParser.prototype.parse = function () {
"use strict";
var thisObj = this;
$.get(this.feedUrl, function (data, textStatus, jqXHR) {
if (textStatus == 'success') {
var xml = jqXHR.responseXML,
//lastBuildDate = new Date($(xml).find('lastBuildDate').text());
items = $(xml).find('item');
items.each(function () {
var pubSingle = thisObj.makeObj($(this).find('pubDate').text(),
$(this).find('link').text(),
$(this).find('title').text(),
$(this).find('description').text(),
$(this).find('encoded').text(),
$(this).find('commentRss').text(),
$(this).find('comments').last().text());
thisObj.pubArray.push(pubSingle);
});
console.log(thisObj.pubArray); // OK
}
}, 'xml');
console.log(this.pubArray); // Empty
return (this.pubArray);
};
MyParser.prototype.makeObj = function (pubDate, pubLink, pubTitle, pubDesc, pubContent, pubComCount, pubComLink) {
"use strict";
var pubSingle = {};
pubSingle.pubDate = new Date(pubDate);
pubSingle.pubLink = pubLink;
pubSingle.pubTitle = pubTitle;
pubSingle.pubDesc = pubDesc;
pubSingle.pubContent = pubContent;
pubSingle.pubComCount = pubComCount;
pubSingle.pubComLink = pubComLink;
return (pubSingle);
};
}
this.init_ok = true;
}
If you look at the console.log(), you'll see that the line // OK is outputting my array correctly.
But later, when returning from $.get, my array is empty.
Does anybody have an idea why, and how to correct that please?
This is not a problem with variable-scope. The problem here is that you're working with asynchronous flow and you're not thinking correctly the flow.
Let me explain:
When you do your .get, you fire a parallel asynchronous process that will request information from the browser, but your main program's flow keeps going, so when you get to your "return" statement, your array has not been filled yet with the response from your get method.
You should use your array from inside the get callback and not outside of it, since you can't guarantee that the array will have the information you need.
Does it make any sense?
Let me know!
Further explanation
According to your comments, you're still doing something like this:
var results = MyParser(feed_url);
//code that uses results.pubArray
And you cannot do that. Even though you're setting your "pubArray" inside your .get callback, you're trying to use pubArray right after you called MyParser and that's before the .get callback is called.
What you have to do, is call your next step on your program's logic from within the .get callback... that's the only way you can be sure that the pubArray is filled with proper data.
I hope that makes it clearer.
This is because your line
console.log(this.pubArray); // Empty
is being called directly after you issue your Ajax request; it hasn't had time to fetch the data yet. The line
console.log(thisObj.pubArray); // OK
is being called inside the Ajax callback, by which time the data has been fetched.
Thank you all, and particulary #Deleteman .
Here is what I did:
$.get(this.feedUrl, 'xml').success(function () {
thisObj.handleAjax(arguments[0], arguments[1], arguments[2]);
$(document).trigger('MyParserDone');
}).error(function () {
$(document).trigger('MyParserFailed');
});
Then, when i enter "HandleAjax", i'm back in my object context, so "this" refers to my object and the right properties. The only "problem" is that I have to set a listener (MyParserDone) to make sure the parsing is finished.

Categories

Resources