Iron Router: Load js script after template has been rendered - javascript

I'm trying to load a javascript file (using IRLibloader) after the Iron Router has rendered the template:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
});
Router.route('/', {
name: 'landing',
template: 'landing',
onBeforeAction: function () {
var googleAPI = IRLibLoader.load('http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false');
var fancyInput = IRLibLoader.load('/js/fancyInput.js');
var geoComplete;
if(googleAPI.ready()){
geoComplete = IRLibLoader.load('/js/jquery.geocomplete.min.js');
}
if(googleAPI.ready() &&
fancyInput.ready() &&
geoComplete.ready()){
console.log('All ready');
this.next(); // Render the page when all the libraries are ready
// Testing this here
if(Meteor.isClient){
console.log("Meteor.isClient");
IRLibLoader.load('/js/landing.js');
// Set places autocomplete
Template.landing.rendered = function(){
$('section :input').val('').fancyInput()[0].focus();
$('section :input').geocomplete();
console.log("loading.js ejecutandose (after render)");
}
}
}
}
});
But when I browse localhost:3000, the layout gets rendered, the googleAPI, fancyInput and geocomplete libraries are loaded too since the 'all ready' message gets printed at console, and landing.js also gets loaded (since it loads the background image and the message 'Meteor.isClient' also gets printed).
But then, the 'landing' template never gets rendered. Its content does not appear, and the console message inside the Template.landing.rendered never gets printed. This is the template.js file:
<template name="landing">
<img id='logo' src="img/logos/logo.png">
<div id='content'>
<section class='input'>
<div>
<input type='text' placeholder='Type text here'>
</div>
</section>
</div>
</template>
I also tried loading landing.js with onAfterAction, which seems to happen before the onBeforeAction according to the Firebug console. How strange!
I can't understand why the template is not being loaded, since no error appears at meteor console. Any idea?
EDIT: it does work if I remove the layout, which looks like this:
<template name="layout">
<head>
<title>Welcome to my app</title>
</head>
</template>
What's wrong with this layout?

So, I think you might be overthinking this a little. Why not use existing packages for these libraries? Aside from being significantly easier to use, some of that 3rd party code would get minified into the main app js file instead of making additional HTTP requests to download them.
For example, dburles:google-maps gets you the Google Maps API and extra libs of your choice (with the option to only load on specific routes) and jeremy:geocomplete gets you Geocomplete (which automatically installs that maps package as a dependency). See the jeremy:geocomplete README for implementation.
As for Fancy Input, why not create a simple Meteor package wrapper for that so you can just meteor add fancy-input?
Also, your Template.landing.rendered callback should not be in an onBeforeAction. Ideally, it should be in its own file with other code for the landing template.

Related

How can I add a script function to React

I am trying to add an external application Chameleon onto my react application and for that I have to add the javascript function to my application.
I only want it to be called in specific situations so I don't want to load it in my index.html. I tried adding it to the render function of my component as:
render() {
return(
<div>
<head>
<script type="text/javascript">/* Chameleon - better user onboarding */!function(t,n,o){var a="chmln",c="setup identify alias track clear set show on off custom help _data".split(" ");n[a]||(n[a]={}),n[a].accountToken=o,n[a].location=n.location.href.toString();for(var e=0;e<c.length;e++)!function(){var t=n[a][c[e]+"_a"]=[];n[a][c[e]]=function(){t.push(arguments)}}();var s=t.createElement("script");s.src="https://fast.trychameleon.com/messo/"+o+"/messo.min.js",s.async=!0,t.head.appendChild(s)}(document,window,"TOKEN");
chmln.identify(USER.ID_IN_DB, { // Unique ID of each user in your database (e.g. 23443 or "590b80e5f433ea81b96c9bf6")
email: USER.EMAIL });
</script>
...
...
</head>
</div>
)
}
But the above doesn't seem to work. I tried the same inside a helmet but no luck. Both of them show an error for
SyntaxError: Unexpected token
Is there a way I can load this function in a specific component or do I have to do it in the index.html?
You seem to have a strong misunderstanding of what react is for and how it is used.
1) There should only ever be 1 head element on the page, and it should be in index.html not in the rendered output of a component.
2) Having a component render a <script> tag goes against the point of using react.
What you need to do is import the code you need into your component:
import './path/to/file.js'
And then from there chmln should be available on the window object
window.chmln.identify()

Two different layouts in aurelia app

I'd like to use two separate layouts for my aurelia app. Difference between them is that one doesn't have a sidebar. Currently I'm using one layout file defined as below:
<template>
<div class="container">
<router-view></router-view>
</div>
</template>
If an active route needs this sidebar to appear I'm just putting it into its view.
What I'd like to achieve is to add another layout that would have this sidebar by default:
<template>
<require from="../common/elements/sidemenu/sidemenu"></require>
<div class="container">
<sidemenu></sidemenu>
<router-view></router-view>
</div>
</template>
So the question is - how to do this? Is it even possible with an aurelia app to have multiple layouts (or master pages, however you call those)?
Use aurelia.setRoot()
You can manually set up your application by specifying a script with configure instructions in your index.html. Typically, this is set to main.
index.html
<body aurelia-app="main">
In this script you can specify a root view model using aurelia.setRoot('root'). If no argument is provided, the convention is to use 'app'.
main.js
aurelia.start().then(() => aurelia.setRoot());
However, you can inject the aurelia object anywhere in your application, and call the setRoot function at any time to load a different root view model.
home.js
#inject(aurelia)
export class HomeViewModel {
constructor(aurelia) {
this.aurelia = aurelia;
}
doStuff() {
this.aurelia.setRoot('withSidebar');
}
}
One common use case for this is having a login page, and I've created a complete template for this use case that you can review, clone, or fork here: http://davismj.me/portfolio/sentry/

Why does Meteor get cranky with this IronRouter code?

In response to the comment by AutumnLeonard here, I tried a minimalistic implementation of the idea. I first added the iron router package via "meteor add iron:router" and then tried this code:
blogtest.html:
<head>
<title>blogtest</title>
</head>
<body>
<h1>This is really something, isn't it!?!</h1>
{{> thought}}
{{> anotherthought}}
</body>
<template name="thought">
<p>THis is a random thought.</p>
</template>
<template name="anotherthought">
<p>THis is another random thought.</p>
</template>
blogtest.js:
Router.route("/:blog_post_title", {template: "thought", name: "thought"});
Router.route("/:blog_post_title", {template: "anotherthought", name: "anotherthought"});
if (Meteor.isClient) {
// counter starts at 0
Session.setDefault('counter', 0);
Template.hello.helpers({
counter: function () {
return Session.get('counter');
}
});
Template.hello.events({
'click button': function () {
// increment the counter when button is clicked
Session.set('counter', Session.get('counter') + 1);
}
});
}
if (Meteor.isServer) {
Meteor.startup(function () {
// code to run on server at startup
});
}
(the top two lines are the only ones I added; the rest are superfluous but harmless "boilerplate" code left over from the default meteor app)
...but on trying to run it, it fails with throbbing blue and purple growlings emanating from the command prompt, to wit:
W20151007-09:25:00.634(-7)? (STDERR) Error: A route for the path "/:blog_post_ti
tle" already exists by the name of "anotherthought".
(why does it complain about "anotherthought" but not about "another" if my IronRouter syntax is wrong here?)
W20151007-09:25:00.635(-7)? (STDERR) at blogtest.js:2:8
(line 2, char 8 is the "r" in "Router.route" on the second line...???)
W20151007-09:25:00.635(-7)? (STDERR) at C:\Misc\blogtest\.meteor\local\build
\programs\server\app\blogtest.js:37:4
(there is no line 37 in blogtest.js ...???)
UPDATE
Okay, so I changed the HTML to:
<head>
<title>blogtest</title>
</head>
<body>
<h1>Here's a thought:</h1>
<!-- {{> thought}}
{{> anotherthought}} -->
</body>
<template name="thought">
<p>This is a random thought.</p>
</template>
<template name="anotherthought">
<p>This is another random thought.</p>
</template>
...and the routing code to:
Router.route("/thought", {template: "thought", name: "thought"});
Router.route("/anotherthought", {template: "anotherthought", name: "anotherthought"});
...and it no longer fails to run; in fact, I do see what I would expect to when I enter "http://localhost:3000/thought", namely:
Here's a thought:
This is a random thought.
...and what I expect with "http://localhost:3000/anotherthought", too, namely:
Here's a thought:
This is another random thought.
However, I see this at localhost:3000 (the default URL):
Here's a thought:
Oops, looks like there's no route on the client or the server for url: "http://localhost:3000/."
So what do I need to enter so that the "Oops" goes away? What Route.route() is needed?
you define two same route ("/:blog_post_title"), cannot be same I guess. Maybe you can try to change one of them. maybe another one you can define as "/:blog_post_title2".
just my 2 cents
You do not sound happy:-( Meteor is a bit of a learning curve, but for me it's been very worth it.
I see a couple of things here that might be tripping you up.
Templates vs Routes: The difference between a route and a template.
A template is like a recipe for filling in some HTML. Nesting templates in templates helps to break an app into smaller pieces.
A route is like erasing everything and starting over. You essentially drop all the HTML, and start with a new template.
This difference comes from how web apps were built before, and is still very useful now.
Template Includes: you wouldn't use a route like this: {{> thought }}. That's the syntax for including a template.
This would import HTML templates (like you're defining). You don't need a route to make this work.
Routes: Here, routes are defining the top template. They wipe everything (with exceptions like Session variables) and start over.
The path is important because it identifies the place in the app. This let's users bookmark places in the app.
Having two routes with the same path is an error for sure. Which should be used for the bookmark? Delete one of the routes to move forward.
Body: You can't stuff things in the body like you're doing at the top of your HTML. (Well you can, but it's not best practices:-) Meteor basically appends the routes template to the tag. It's was jarring to not define a <body>, but that's how it works.
Change the <body> to <template name="main">, and fix the </body>
Then add the template to a route:
Router.route("/", {template: "main"});
This might not work 100%, but it should get you past some of these blocks you're having.
Also, relax and have fun! After coming from PHP and Angular/Express, Meteor is a lot of fun!
You might try the Discover Meteor book. It was a great way for me to get started. Just took a couple days to get started.
It turns out that it's easier than what I was trying; most of that fancy-pants stuff was effluvia.
All I need in the *.js file is:
Router.route('/');
Router.route('/thought');
Router.route('/anotherthought');
And the following HTML works as expected (showing just the H1 for "localhost:3000", and showing the appropriate template in addition to the H1 when I append "/thought" or "/anotherthought" to that base URL.
<head>
<title>blogtest</title>
</head>
<body>
<h1>Here's a thought:</h1>
</body>
<template name="thought">
<p>This is a random thought.</p>
</template>
<template name="anotherthought">
<p>This is another random thought.</p>
</template>
So to create a meteor app to which I can add content that I can share, all I need to do is:
0) At the command prompt, enter "meteor create <projectName>", such as: "meteor create thoughts"
1) After cd'ing to the directory (which is the projectName), as directed, enter "meteor add iron:router"
2) So that your "raw" URL doesn't throw an iron exception, add this to your .js file:
Router.route('/');
3) Add a new template to the .html file each time I want to make something public.
4) Then (each time), add a routing directive in the .js file with the name of the template; e.g., if you add this template:
<template name="thought">
<p>This is a random thought.</p>
</template>
...you would add this line to the .js file:
Router.route('/thought');
5) Make your meteor app public by, at the command prompt, entering "meteor deploy "; e.g., you could enter "meteor deploy thoughts" or "meteor deploy rompecabeza" (the deployed name doesn't have to match the project name).
6) Advise whoever you want to see it to "point their browser at" your URL, such as, "Hey, gang! Go czech out '<your URL, with the appended template name>'! You can give me a penny later!"
That's all there is to it.
For example, I created a static site that serves up a few of my photos. They can be seen via these links:
http://dplatypus.meteor.com/pinnacles
http://dplatypus.meteor.com/garrapatabeach
http://dplatypus.meteor.com/garrapataturnout
http://dplatypus.meteor.com/mcwayfalls
http://dplatypus.meteor.com/pfeifferbeach
Alternatively, you can just click the links above from dplatypus.meteor.com

Are'nt we Allowed to write html codes if we use backbone.js?

I am learning backbone.js and I have seen some examples like this one.Here the user has not written much html codes inside the editor.html.Only 4 lines of code.But for colour change,size change etc he has done inside editor.js
Please help me understand what all codes we need to keep inside .html file
<div id="page" style="width:2000px;height:2000px;">
<button id="new-rectangle">New Rectangle</button>
<button id="new-circle">New Circle</button>
</div>
You should aim to put all your html in .html file(s). As an app grows, it will help you to keep them separate. The example you link to is a 'simplified' version - this is not how you would structure things in an actual app. You would load html from templates in the render function. A (though this is also simplified as I am relying on script tags) pattern would be:
HTML file:
[...SOME HTML...]
<script type="text/html" id="template-contact">
<div class='contact'>
<h1>Here's my template code</h1>
<strong>name</strong>
<span>email</span>
</div>
</script>
Then in your Backbone view render function:
render: function() {
template: _template($('#template-contract').html(),
this.$el.html(this.template());
return this;
}
Then somewhere else in your Backbone code you create a new instance of the view and render it.
var example = new view_name();
example.render(); //This loads the html template
If you need to dynamically load the html from a server, you can use underscore (or whichever template engine you are using) tags in your template '<%>' and use models. This is best explained in Addy Osmani's book Developing Backbone.js Applications which, incredibly, is free. Here's the link to the relevant section
Whatever you wants to display on the browser you can keep it in .html file and logic to update the dom on run time should be in .js file.

How to make something happen after a template has rendered in emberjs

So the concept is simple: You come to the app, you have a default template, with a default navigation element. You click a link in that navigation element it renders a new template: #/rails.
From here the default navigation needs to be hidden, and your new nav needs to be rendered.
The way i attempted to approach this, seems a bit silly: what I did was,
SG.Router.map(function(){
this.resource('rails');
});
$(document).ready(function() {
if($('#rails-nav').length !== 0){
$('#main-nav').hide();
}
});
Now the issue with this is that if you go from the default application template, to the rails template via the link - you get two navs unless you refresh that page. My friend stated that I should use something like:
{{outlet nav}} and then render a navigation based on template. The issue is I don't know how to set this up and I have been looking all over the ember site.
Could some one help me out?
If i understood correctly, when you say default template you mean the application template, where all other templates are rendered within its {{outlet}} helper.
There are several approaches to achieve what you want, but a simple one i think would be to use the index template as your default template. In this case evertyhting will be much simpler and work as you require, since you can specify whether the navigation element is shown by placing it inside a template or not.
http://emberjs.jsbin.com/sume/1/edit
hbs
<script type="text/x-handlebars">
<h2> Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
This is the default template using <i>index</i>
<br/>
<br/>
<span style="background-color:grey">this is the nav part {{#link-to 'rails'}}go to rails{{/link-to}}</span>
</script>
<script type="text/x-handlebars" data-template-name="rails">
this is the rails app
</script>
js
App = Ember.Application.create();
App.Router.map(function() {
this.resource("rails");
});
Also to make this answer a bit more relevant to the title of the question, in order to do something when a template has rendered one way would be to use the didInsertElement callback of the View class.
App.RailsView = Ember.View.extend({
didInsertElement:function(){
if($('#rails-nav').length !== 0){
$('#main-nav').hide();
}
}
});
http://emberjs.jsbin.com/dido/1/edit

Categories

Resources