Re-initiate a javascript function on an asynchrously loaded template in angularjs - javascript

I'm fairly new to AngularJS v1.8, so please excuse my ignorance here.
Using a component to load a template into the dom loses any event bindings that exist.
Is there a way to re-initiate these functions, i.e. a JavaScript library loaded on page load?
Or perhaps allow these events to stay 'live' across asynchronous dom manipulation?
I have a number of libraries included on page load and wish to create components to include partials without recreating ALL the functionality I already have.
In my index file I have a basic nav bar and the js to manage events.
<nav-bar></nav-bar>
My angular component looks like this (simplified):
app.component("navBar", {
templateUrl: "components/navBar.html",
});
The included js library has multiple functions that bind events to classes, so this is what is not working:
data-kt-menu-trigger="click"
FYI, this is part of a theme with a huge library of js, surely one can re-initiate these functions and make them available to any dom asynchronously loaded?
Also, we have chosen to stay with v1.8 for various reasons.

Related

What's best practice re. isolating JS to pages/actions within a Rails project?

For the first time as a jnr progammer I'm looking at how to write my js code so that it's isolated to certain pages within my Rails app. I figure this is a sensible thing to do for the purposes of;
a) certain js i write I only want to target a certain element on an individual page, not other elements on other pages within the same controller that may get picked up due to using a class selector for example and marking every single thing with unique id's doesn't seem too neat. (I see that rails already has controller isolation through the naming of js files by controller, but further dividing things up into action/page names js files doesn't sound nice either!).
b) perhaps in finding a solution to only running js on certain pages it could mean that the js only needs to be loaded on certain actions thereby saving on load times.
There's a well attended question here with folks approaches here but most answers are 6 years old now and another nice post about the so called 'Garber Irish method of Dom ready execution' here that sounds quite nice, but again this is quite old now and all based on Rails 3...
So without wanting to create duplicate content I'm seeking to get a refreshed answer to this same question and find out whether there's a best practice now established these days.
Thanks
Convention:
Rails when using scaffold generator by default creates corresponding
app/assets/javascripts/MODEL_NAME.coffee
app/assets/stylesheets/MODEL_NAME.scss
which separates JS and CSS logic by "controller" name
Personal Preference:
Rather than controller-based segregation, I prefer layout-component-based segregation. Best explained through a sample code below:
app/assets/javascripts/application.js
//= require_tree ./layouts/
app/assets/javascripts/layouts/__shared.coffee
// WRITE GLOBAL JS LOGIC HERE FOR ANY LAYOUT
app/assets/javascripts/layouts/application/__shared.coffee
// WRITE GLOBAL JS LOGIC HERE ONLY FOR THIS "application" LAYOUT
app/assets/javascripts/layouts/blog/__shared.coffee
// WRITE GLOBAL JS LOGIC HERE ONLY FOR THIS "blog" LAYOUT IF YOU HAVE ANOTHER layout such as "layouts/blog.html.erb"
app/assets/javascripts/layouts/application/components/header.coffee
// WRITE JS code here for the header component
app/assets/javascripts/layouts/application/components/footer.coffee
// WRITE JS code here for the footer component
app/assets/javascripts/layouts/application/components/users/__shared.coffee
// You can also divide a component into subcomponents just like this
// WRITE JS code shared amongst all users subcomponents
app/assets/javascripts/layouts/application/components/users/form.coffee
// WRITE JS CODE HERE regarding the form that creates or updates a User
app/assets/javascripts/layouts/application/components/users/list.coffee
// WRITE JS CODE HERE regarding the table listing all users
You also structure the CSS files in the same way, matching the components

Is it possible to influence a single Angular app from multiple JS scripts?

Quick Summary:
I need to allow two script files to handle different operations for the same angular app. One needs to initialize the app, the other needs to assign a templateCache object to a piece of JSON in localStorage.
Context:
I have several python files which compile/generate html and I have constructed an angular app with this emitted html for my site (which uses CGIs).
The basic construct of the site comes pieces of HTML, which fit together like so:
|------------Header---------------|
|-Navigation-|------Content-------|
|-Navigation-|------Content-------|
|-Navigation-|------Content-------|
|------------Footer---------------|
My Header creates the <head> tag, instantiates my ng-app and uses $templateCache to set up a template that I call from my Navigation code. I had to go with templateCache instead of ngView and ngRoute due to some limitations with how the CGIs emit the html, and the order in which this happens.
My "Navigation" python/html sets up my app with JS like so:
<script>
var responsiveCatalog = angular.module('responsiveCatalog', ['ngStorage']);
....controllers...
....config, etc....
</script>
This Navigation also includes my default templateCache object:
<div ng-include=" 'responsiveItems.html' "></div>
This is all working to show my first templateCache object in the Content section. However, I need to grab many pieces of information from the python generator for the "Content" section (a totally separate file from the "Navigation"), store this data as JSON in localstorage (hence the inclusion of the ngStorage module), and call that as my second templateCache option.
I am not actually sure that I can use two separate instances of Javascript to reference and influence the same Angular app. I know this seems like bad practice, but I am trying to prevent the need to tear down a huge piece of legacy architecture to influence the angular app from two Javascript files in harmony.
Thanks in advance.
You can do
angular.module('myAppName').controllers.... in different files, just make sure the myAppName the same. Bug I don't feel like it work with config, no time to test. If you need any communication between them, check $emit and $broadcast.

Should I recreate all my page from scratch (html and css) if I begin using React/flux?

I have alreayd built a few pages of my app. As i need a javascript framework and sub second dynamic pages I think I'll try React/Flux.
The thing is despite much reading, I don't fully understand if you can keep my EXISTING codebase (html/js) and only use React (jsx , modules) on certain blocks of the web page that need interaction with database/dynamic actualization?
Let's take an example:
my page has a lot of stuff : bootstrap I adjusted a lot(with css) that is actually using behind the scene javascript/the DOM ex for dropdowns, and other stuff), respond.js for enabling media queries on ie8 (using I guess the DOM), and many third party tools like intercom.io or even google analytics js tracking window on the bottom of my screen.
you can see here what the pages look like.
My need: I just need dynamic adjustments and real time features on the block (D), all the other, the header (B), intercom(C) and the rest could stay like they are, it would save me some much time if i can keep them in their current html code.
So here are my question:
(1) do I have to convert EVERYTHING on the page on react or only put in jsx/react the block (D) and keep the rest as it is ?
Related to (1) I want to leverage the main advantage brought by React (the virtual DOM and the diffs), would I still be able to use it EVEN if the whole page is not on React ?
If the answer is basically "it's all or nothing, you've got to do it ALL in react jsx and redo your whole page", convert your html and find alternatives to all your js scripts that use the DOM such as dropdowns, light boxes, intercom.io script, google analytics scripts then is it hard? i mean or can i keep the css and just use this to change the html http://facebook.github.io/react/html-jsx.html ? that would be really easy but i fear there is a catch here...:)
In terms of the view layer of your app everything can be done with React
(Yes react can do everything you require)
The first thing I would suggest is to head to the react site for the docs, do a few tutorial use Google & YouTube and then start to re-build your app from fresh with react but not entirely. (Use JSX).
Because you now understand how React works and how to use props and states you will likely end up merging fragments of your app at a time.
The most important thing to consider is context. React is simply Javascript so you can bind, call and apply any objects from your existing app.
var blockA = React.createClass~
blockB = React.createClass~
blockC = React.createClass~
blockD = React.createClass~
React is just components, each block is a component.
But I can't stress more, understand the basic principles of react, it's not hard at all.
Edit...
YES use JSX I thought it was stupid initially but it's excellent!
With DOM manipulation it's all or nothing. React uses its copy of the DOM to manipulate the actual DOM faster. For parts of you code that doesn't touch the DOM it will not make a huge difference in React but React has a beautiful workflow by passing state changes down to its component's children. Really it's up to you but If you are using React do all DOM stuff in react. 70+% of what you are trying to do is likely DOM manipulation.
My advice in general, don't think too much about how "hard" it will be. Think about how quick you can learn the basics. It's quite easy to grasp.
I am new to React, but from what I've gathered you may sprinkle in React code as desired. You do not have to re-write your entire application. This includes the ability to use the features you outlined wherever you need them.

How do I rename or selectively load angularJS?

We have a product that is a widget people load onto their site, which consists of a single JS file that also needs angular to run, so angular is bundled into the JS file.
However, if a site already is using and loading angular themselves, when they load our widget they get an error which kills everything with the following:
WARNING: Tried to load angular more than once
Which makes complete sense since angular was indeed loaded more than once.
What we'd like to do is either of the following:
In our script, rename / namespace angular so it does't conflict with
the host sites already loaded angular, or
Detect if angular is
already loaded, and if so don't load angular ourselves.
To show examples of our code would be difficult since it's spread over about 20 files etc, however it's based off the following angular seed project which uses requirejs to load everything, then we're compiling to a single file: https://github.com/tnajdek/angular-requirejs-seed
Would really appreciate any feedback / tips / solutions
NB This is not a duplicate of any "check if angular loaded correctly" type questions, angular is packaged inside our widget js, the issue comes when angular is also already loaded by the parent page. We need a way to rename angular inside our package.
I'd advise taking a look at this answer, it has to do with a chrome extension running in the same circumstance. The idea here is to separate your loading of angular from the website's, and it assumes that your widget will be loaded after the main content of the page has been loaded.
If you are loading in html content with an ng-app directive or ng-controller, wrap your html content in a container with ng-non-bindable as an attribute.
Angular looks immediately for an element with the ng-app attribute when you load in angular.js. If two ng-apps are present i.e., on your site, and the widget, it will cause errors. Defer the parsing with: window.name = "NG_DEFER_BOOTSTRAP!" + window.name; Then load in your script.
Once your script has loaded, set window.name to '' or whatever it was before.
Individually bootstrap (the term for angular finding an ng-app attribute) your html content using:
var appRoot = document.querySelector('#id');
angular.bootstrap(appRoot, ['angularModuleName']);
And that should do it... Caveat, I have no idea how this would work if your widget Angular is on a different version than the client website, and I've only made it work with extensions, which are a little bit different because they live in their own isolated 'worlds'.
That being said, I feel like this should get people going in the right direction when dealing with this problem.

Grails' templates and their DOM

As far as Grails' templates go, do they have their own DOM? Is it different from the DOM of the main GSP(parent GSP) into which a template gets loaded or does the template's DOM become part of the parent GSP's DOM? I'm having a hard time differentiating between these two DOMs and their relationship. Do they both have their own separate DOM ready moments? And so their own separate DOM ready clauses as far as javascript goes? If anyone can please clarify on these points. Much obliged.
GSP, Groovy server pages, are server based. The DOM you are concerned with is the client-side browser DOM. To answer your question, no. The entire HTML document (even if it's made up of several GSP templates) is still one DOM within the browser.
Having said this, however, it also depends on how you are loading the content of the page. I'm assuming you are loading all the content in a single HTTP request.
The separate GSP templates are built into a single HTML document before being sent to the browser.
Grails uses a framework called SiteMesh http://www.sitemesh.org behind the scenes.
Edit:
I guess the answer depends on whether you are using the <g:render template="myTemplate" /> tag from inside a gsp or doing an ajax call and using the render method from your controller like this: render(template: "myTemplate")
The ajax call will inject the html from the template into the browser's DOM.

Categories