Angular 2+ Window attribute undefined - javascript

I'm using an external library that attaches itself to the global window object (window['lib']) once the library's javascript file is loaded by the browser. I'm trying to invoke code using this library whenever a component is loaded, however everytime I try to access the object it is undefined (due to the library not having been loaded). I have tried every lifecycle hook I can think of, however nothing appears to wait for the DOM to be fully ready. For example, I want to do something like this:
ngOnInit() {
window['lib'].doStuff(); // <-- window['lib'] is undefined
}
If I wrap it in a timeout, then it becomes available. However, this looks like code smell and do not want to approach it this way:
ngOnInit() {
setTimeout(function() {
window['lib'].doStuff(); // <-- this works
});
}
What is the best / suggested / "most angular way" to approach this problem? Thanks!

Angular Lifecycle Hook: ngOnInit()
Initialize the directive/component after Angular first displays the
data-bound properties and sets the directive/component's input
properties.
Called once, after the first ngOnChanges().
This is a common problem with Angular. Older methodologies like this one that uses a global variable on the window object will piss off the way Angular loads the application and also TypeScript (during development). The reason why you have to do window['lib'] and not window.lib is because TypeScript doesn't know anything about the types of window.lib so window['lib'] is a way to force it to work.
The other part is that depending on what type of compilation you're using (AOT vs JIT), that library you're loading may or may not be ready yet (also depends on how you're loading that script/module into the application). As Commercial Suicide mentioned, you could try some of the other Angular Lifecycle Hooks but more than likely, you're going to end up settling on setTimeout. You actually don't even need to define the timeout period or you can pass 0ms (as you've done in your code). Angular just wants you to hold off on calling that function until the DOM it's finished rendering.
I personally can't wait until all the jQuery-like libraries are converted into proper ES6 modules. The days of just throwing a script tag at the bottom of the body are long gone.
setTimeout
How to get a reference to the window object in
Angular
Relevant Thread

Related

Does JIRA have a method to call JQuery(window).ready?

We have a Jura plugin written by ourselves, and in it's vm template at the very end there's the following code:
AJS.$(window).ready(function(){
doSomeThing();
});
Inside of this method we are loading some server side data and initializing internal js objects. For some strange reason this specific method doSomeThing is being called twice. Moreover, vm template is also being called twice, owerwriting first template initialization state (but template may be already initialized and contain some data at this point). I don't get it why it's made this way and how to work around this. If someone faced similar thing before and knows what to deal with it - please respond. Much appreciated.
We've found a reason of such bahavior - it's Backbone. Jira creates an element using Backbone View, which calls AJS.$().ready second time during initialization. We stopped usage of this element after our investigation

onrender vs init in Ractive.js

I recently started trying out Ractive.js. I was particularly interested in its components. One of the things I noticed immediately is that many of the examples are using the init option. However when I try to use the init in my code I get a deprecation notice and it then recommends using onrender instead. onrender however had far fewer examples than init and some of the functions such as this.find weren't available inside onrender. I looked through the Github issues but couldn't find any reasoning behind this change or what the suggested path forward for selecting elements specific to a component was.
I created a test pen to try creating a recursive component with the new API but I had to resort to using jQuery and an undocumented fragment api to select specific DOM nodes I needed to manipulate. I feel this is against how Ractive expects you to do things, but I couldn't figure out what was expected of me with the existing documentation.
What's the major differences between the init and onrender options and how does onrender expect you to handle manipulating specific elements and their events within a component?
You can use this.find() inside onrender (if you can't for some reason, you've found a bug!).
We split init into oninit and onrender a while back for a number of reasons. Those examples you mention are out of date - are they somewhere on ractivejs.org? If so we should fix them. You can find more information about lifecycle events here on the docs, but the basic difference is this:
init was called on initial render (assuming the component was rendered, i.e. never in node.js, if you were doing server-side rendering)
oninit is called on creation, immediately before rendering. It is called once and only once for any Ractive instance, whether or not it gets rendered. It's therefore a good place to set up event handlers etc. The opposite of oninit is onteardown, so you can use that handler to do any cleanup if necessary (or use this.on('teardown'...) inside oninit).
onrender is called whenever a component is rendered. This could happen more than once (if you unrendered, then re-rendered, etc) or not at all. If you need to store DOM references etc, this is the place. The opposite of onrender is onunrender.
I did a fork of your codepen, replacing the jQuery stuff with more idiomatic Ractive code to show how you'd do it without storing DOM references.

How to change current template/route by an external script?

In my ember.js-app, Ive got one template which includes a javascript-jQuery-script. Within this script I want to call ember to read out some variables, safe them, and then change the template
Like so
finishedGame = function() {
// ember create model-entry by using "this.points"
// ember change the template to "game/credits"
};
How can I use ember to hook into an independent-running script and start functionality like switching templates etc. or ist it possible to access the controller functions from elsewhere than the ember-scripts itselv?
One very bad approach would be to use a global variable to do this and then observe it from within Ember as described in this answer, then you can trigger whatever action you require, but this is definitely not recommended.
As this other answer states, if you find yourself thinking a global variable is the best solution it's a sign that something should be refactored.
So in this case I would go with calling the finishedGame() function from within an Ember scope, like the controller (probably with Ember.$ if it is jQuery) and have this function return the values you want to save, then issue a call to a transitionToRoute method (take a look at this documentation).

Meteor: how can I avoid checking for the existence of a variable or property everywhere?

When programming in Meteor I often find myself having to sprinkle typechecks or existence checks a bunch when writing Template helpers (at least under a couple very common conditions).
A helper for one template depends on a collection loaded by a different template
Any time a template helper operates on a piece of the DOM that another template is responsible for rendering into existence
For example (in the first case):
Template.example.rendered
rev1 = getRev(revId1)
revText1 = html2plain(rev1.text)
where getRev is doing an operation on the Revisions collection that may or may not be loaded by the time the example template is first rendered. So rev1.text will sometimes throw an exception because getRev ends up returning null or undefined if called before Revisions is loaded.
I then end up having to check a ton of variables/objects throughout my code for existence before using any of their properties just to be safe.
I could imagine using a router to not render my example template until after a different collection is ready (but for nested templates, and Session variable changes this doesn't work so hot).
I could imaging wrapping the helper code in a if (isCollectionReady) which might help but doesn't seem best practice.
The question is: Is there a canonical or best practice way to, identify these situations, code for them, or avoid this altogether?
Meteor is designed such that its templates are reactive, so that in most cases you shouldn't need to do DOM manipulations on them. As the underlying data changes, the templates automatically rerender so that they're always showing the latest data. Take a look at the examples in the Meteor docs: they don't use any DOM manipulation code. The templates put the data into the right places, and that's all they need.
In my experience there are two common reasons to need to put code into rendered:
You're loading a widget that needs to be initialized after the template is rendered and ready, like a <select> replacement.
You're doing animations. (In this case, I usually tell my template to put everything in its proper place but with a CSS class that hides the elements, and then all rendered does is animate the reveals.)
It's usually fine for a template to render before its subscription has loaded; at worst, the template will just render blank and then rerender as the data streams in. Also remember that you can subscribe from client-side code other than a template helper, for example Meteor.startup on the client side. Finally don't forget about the created helper; if you really want to wait until a template is loaded before subscribing, that would be a better place to subscribe than rendered, as it gets called sooner.
What DOM manipulations are you doing and why? Assuming you're not using widgets or animations, chances are that you can achieve what you want by using templates on their own without any additional manipulation code.

dojo style developement

I'm having difficulty wrapping my head around dojo style of coding. The reason I am drawn to it is because of its class style coding. I have done AS developement and some java so it makes sense to me to be drawn to it. I have done some jquery style DOM work but I require a more framework based setup for a project I'm starting.
My question is should I be creating everything as classes with the declare and then requiring them when needed. Or could I write closure type functions with namespaces just like regular javascript modules. I'm confused.
Example I want to have a group of methods that take care of managing data. Then I want to have another collection of methods that handle special ajax calls. Would I create a class with declare for each of these groups of methods, in separate js files. Then in my app.js which is my application class where I'm handling the initialization of all my classes, would I require both those classes before dojo.ready(){}
then once the ready method is called I can start to use those classes.
Can someone set me straight here before I dojo out.
Does require make a load request for that js file and if so do you always have to use the ready method. If so is it best to require a bunch of your classes up front at the start of your application initialization.
Technically for what you're wanting to do, you could go either way - using dojo.declare or simply creating an object with function members. I'd be inclined to do the latter, since dojo.declare's elaborate inheritance considerations will be total overkill that you won't be making use of in this case, and it doesn't generally make sense to be instantiating anything when you just want to group some utility methods together.
For modules that simply group utility methods together, I'd be inclined to do something along these lines:
dojo.provide('my.utils');
my.utils = {
doSomething: function(){
/* do something... */
},
doSomethingElse: function(){
/* do something else... */
}
};
RE loading, if I'm reading you right, then yes, you have the right idea. In your web page, you would dojo.require(...) the modules your page requires (perhaps just one, if you have all your other dependencies further required within it). Then, any code in the page that expects these modules to be loaded should be within a function passed to dojo.ready. This ensures that even in cases where modules are asynchronously loaded (i.e. using the cross-domain loader), your code will still work. dojo.ready specifically waits for (1) the DOM to be ready and (2) all dojo.required modules up to that point to be loaded.
Note that within modules themselves, you do NOT need to enclose code in dojo.ready for the sake of waiting for dojo.required modules to load; this is figured out by the loader automatically. (However, if some logic in your module needs to wait for the DOM to be ready, you would still rely upon dojo.ready.)
I've written more about dojo.ready in the past; maybe it'll be a helpful read: http://kennethfranqueiro.com/2010/08/dojo-required-reading/

Categories

Resources