Custom Layout for a specific router not displaying in Meteor with Iron Router - layout

I want to use a different layout template for pages such as login, 404, and other pages. However, when calling this template in my route (using Iron Router), it appears to be ignored and instead uses the default template. How can I update this so that it uses the intended layout?
This is the custom layout I want to use
<template name="UtilityLayout">
<div class="ui centered grid">
<div class="six wide column">
{{> yield}}
</div>
</div>
</template>
My general Iron Router Config:
Router.configure({
layoutTemplate: 'AppLayout',
loadingTemplate: 'Loading',
notFoundTemplate: 'NotFoundLayout'
});
This is the before hook where I am calling the route
Router.onBeforeAction(function () {
//redirect to /login if a user is not signed and if they are not already on login (to prevent a redirect loop)
if (!Meteor.userId() && (Router.current().route.getName() !== 'login')) {
this.redirect('login');
// I also tried Router.go('login');
} else {
this.next();
}
});
This is the route where I am referencing the custom layout (that appears to be ignored):
Router.route('/login', { name: 'login'}, function(){
this.layout('UtilityLayout');
});

Related

VueJS getting the page to accept UID & token

I'm trying to get an activation link from an email to successfully pass it's UID and token to a vue page where it'll get authenticated.
I have my folder structure set up currently like .../registration/activate/_uid/_token.vue, but that causes the registration link to bring up a 404 page.
I've tried setting up to /_uid/_token/_token.vue with the extra token to see what'll happen, and it lets token.vue render, but I don't think the params are being passed. I'm also getting a "Duplicate param keys in route with path: "/registration/activate/:uid?/:token?/:token?" error in console.
<template>
<v-container>
<v-card v-if="status === 'pending'" class="pa-8 text-center">
<p class="title">Please wait</p>
<p class="body-1">Checking registration status...</p>
</v-card>
<v-card v-if="status === 'success'" class="pa-8 text-center">
<p class="title primary--text">Activation successful</p>
<p class="body-1">You may now log in.</p>
<v-btn color="primary" text #click="navigateToLogin">Log In</v-btn>
</v-card>
<v-card v-if="status === 'error'" class="pa-8 text-center">
<p class="title error--text">Invalid activation token</p>
<p class="body-1">This token is invalid. Please try again.</p>
</v-card>
</v-container>
</template>
<script>
export default {
auth: false,
data: () => ({
status: 'pending'
}),
mounted() {
this.$axios
.post('/auth/users/activation/', this.$route.params)
.then((response) => {
this.status = 'success'
})
.catch(() => {
this.status = 'error'
})
},
methods: {
navigateToLogin() {
this.$router.push('/login')
}
}
}
</script>
Here's an example of a registration link.
http://localhost:3000/activate/MTg/5j2-d0af1770a53f1db2a851
Another part of issue that I can't quite solve, is since I'm using python for my backend should I use a python template to submit the UID and token or figure out a way to send the email where the root is localhost:3000 (my frontend) vs :8000 (my backend).
Currently my settings.py looks like this for the registration link:
'ACTIVATION_URL': 'registration/activate/{uid}/{token}',
the root is localhost:8000 for the whole API. So if I can't figure out how to manually set it to 3000 for just this link, I guess I'll need to use a template right? Any suggestions are welcome!
the problem is your path declaration. In Vue you should declare a param in path like this:
path: "/registration/activate/:uid/:token"
after this if you enter http://localhost:3000/activate/MTg/5j2-d0af1770a53f1db2a851 your this.$route.params should look like this:
{"uid":"MTg","token":"5j2-d0af1770a53f1db2a851"}
and you axios request is fine.
and because yout are sending a JSON to server if your using django you can use this code to get the body of a request:
def avtivate(request):
if request.is_ajax():
if request.method == 'POST':
print 'Raw Data: "%s"' % request.body
return HttpResponse("OK")

iron:router syntax Layout

I am using iron router to render a template within meteor framwork, as i was following probably an outdated tutorial, it seems to me there is a change in syntaxes which i could not figure out.
layout.html
<div class="container">
<div class="row">
<div class="span2">
<p>cell</p>
</div>
<div class="span7">
<p>cell</p>
</div>
<div class="span3">
<p>cell</p>
</div>
</div>
</div>
index.js
function.setDefault ('category', null );
Router.configure({
layoutTemplate:'layout',
yieldTemplates:{
'products':{to:'products'},
'cart':{to:'cart'},
'categories':{to:'categories'}
}
});
Router.route(function(){
this.route('/', layout);
this.route('/products',{
data:function(){
Session.set('category',this.params.name);
},
template:'layout',
path:'/:name'
})
});
The following error occurs
unexpected token (1:8)
Where you have Router.route and use this.route in a function, Router.route should read Router.map however this is deprecated in favour of Router.route (without the map wrapper) as below:
Session.setDefault ('category', null );
Router.configure({
layoutTemplate:'layout',
yieldTemplates:{
'products':{to:'products'},
'cart':{to:'cart'},
'categories':{to:'categories'}
}
});
//You will need to declare a template at the least here so it knows what to render to main area
Router.route('/', {template: "template_name");
Router.route('/products/:name',{
onBeforeAction:function(){
Session.set('category',this.params.name);
this.next ();
},
//you don't need this to be layout
//as you are defining a default layout above
//but you will need to specify a template for the main yield area
template:'template_name'
// you don't need to specify path here as it will use '/products'
//if you want to specify a route name use line below
//,name: 'routename'
});
Where url would be /products/product_name
Where template_name is the template you want to render in your main {{> yield}}
In your layout template you need to place the following for your yields wherever you want to display them
{{> yield 'products'}}
{{> yield 'categories'}}
{{> yield 'cart'}}
{{> yield }} //this is the template you specify in template: 'template_name'
(Done from my phone so can't test but can update later if it doesn't work for you)

Organizing view files in Node.js app

I finished this walkthrough for creating a very basic Reddit clone using the MEAN stack. The app included a few different views, such as a view for all posts, a single post, the login form, and the register form, and all of these views were included in a single file: views/index.ejs.
Is putting all the views together like this common practice, or was it merely for brevity in the tutorial? I was hoping to be able to separate at least the login and register forms from the rest of the views in index.ejs for the sake of organization, but placing them in a login.ejs file in views causes a 404.
Login portion of views/index.ejs
<script type="text/ng-template" id="/login.html">
<div class="page-header">
<h1>Flapper News</h1>
</div>
<div ng-show="error" class="alert alert-danger row">
<span>{{ error.message }}</span>
</div>
<form ng-submit="logIn()"style="margin-top:30px;">
<h3>Log In</h3>
<div class="form-group">
<input type="text" class="form-control" placeholder="Username" ng-model="user.username"></input>
</div>
<div class="form-group">
<input type="password" class="form-control" placeholder="Password" ng-model="user.password"></input>
</div>
<button type="submit" class="btn btn-primary">Log In</button>
</form>
</script>
Login portion of routes/index.js
router.post('/login', function(req, res, next){
if(!req.body.username || !req.body.password){
return res.status(400).json({message: 'Please fill out all fields'});
}
passport.authenticate('local', function(err, user, info){
if(err){ return next(err); }
if(user){
return res.json({token: user.generateJWT()});
} else {
return res.status(401).json(info);
}
})(req, res, next);
});
Login portion of controller
.state('login', {
url: '/login',
templateUrl: '/login.html',
controller: 'AuthCtrl',
onEnter: ['$state', 'auth', function($state, auth){
if(auth.isLoggedIn()){
$state.go('home');
}
}]
})
I don't understand how the views fit together in this app. What is telling the app to find the login template in index.ejs, and how can I redirect the app to look in a different file?
The way they did this is a little strange, but it was most likely for the sake of brevity.
The reason why it's 404'ing is because of how the routes are set up. There's a single route to serve index.ejs, and the rest of the routing is handled client-side through Angular. In fact, the only reason they used ejs is because they wanted to send it using Express' res.render() method most likely. (Although, since it's just HTML from what I saw, instead of actually using any EJS, they could likely just as easily used Express' res.sendFile() method, or prior to 4.8.0, res.send() in conjunction with Node's builtin fs.readFile to send the plain HTML file.
If you wanted to split out the views you'd have to set up server-side routes, but I guess they were dead set on a single-page app. More commonly, views that are rendered on the server-side are split out into individual files, with a main "layout", in which other views are included into.

How can I add a class to iron router default template?

I've been searching all over and haven't really found an answer to this seemingly very simply problem.
I have an app that has a default template
Router.configure({
layoutTemplate: 'appLayout',
});
<template name="appLayout">
<div id="container">
{{> yield}}
</div>
</template>
Then I have a new route called 'reservations'
Router.route('/reservations',{
name:'reservations',
onAfterAction: function(){
}
});
What I'd like to do is add a class to the default container that uses css transitions to animate background color from white to black.
What I've tried so far is onAfterAction
Router.route('/reservations',{
name:'reservations',
onAfterAction: function(){
$('#container').addClass('black');
}
});
Does nothing, no errors, no anything. So I've tried
Template.reservations.rendered = function () {
setTimeout(function(){
$('#container').addClass('black');
});
};
Which works, but flashes and creates routing problems. You can see the routing issues at crawfish.meteor.com. How can I simply toggle a class after the template is rendered?
You can use the rendered event:
Template.reservations.rendered = function() {
if( ! this.rendered) {
$('#container').addClass('black');
this.rendered = true;
}
};
Note that we check and set rendered. The Template instance then has a 'rendered' variable that we use to prevent re-triggering on re-render (which can run multiple times)

Multiple Layouts in Ember.js?

Coming from a Rails background, you can have multiple Layouts - for say, anonymous user pages and then authenticated pages.
Is this possible with Ember?
I've tried declaring a new templateName in my UsersRouter, with no avail.
I've also checked this guide: http://emberjs.com/guides/views/adding-layouts-to-views/
But it doesn't seem to be working :/
You can use {{render}} inside an if helper to show different layouts.
For instance if you have an ApplicationController that has login and logout action handlers, and a corresponding `loggedIn' property.
App.ApplicationController = Ember.Controller.extend({
loggedIn: false,
login: function() {
this.set('loggedIn', true);
},
logout: function() {
this.set('loggedIn', false);
}
});
The you can bind to the loggedIn property inside the application template like so.
<script type='text/x-handlebars' data-template-name='application'>
<button {{action login }}>Login</button>
<button {{action logout }}>Logout</button>
{{#if loggedIn}}
{{render 'user'}}
{{else}}
{{render 'guest'}}
{{/if}}
</script>
Where user and guest are corresponding templates.
<script type='text/x-handlebars' data-template-name='user'>
<h1>User layout</h1>
<div class='box user'>
{{outlet}}
</div>
</script>
<script type='text/x-handlebars' data-template-name='guest'>
<h1>Guest layout</h1>
<div class='box guest'>
{{outlet}}
</div>
</script>
Here's a working jsbin.
Edit: To not use the application route based on some static criteria or loaded via model hooks, you can override the renderTemplate method of the ApplicationRoute.
App.ApplicationRoute = Ember.Route.extend({
renderTemplate: function() {
var loggedIn = false;
if (loggedIn) {
this.render('user');
} else {
this.render('guest');
}
}
});

Resources