I've a template like below
<template name="mainEvents">
<section class="main-events-list events-list js-content-slider">
{{#each events}}
<div class="events-list-item">
<figcaption>
<dl class="clearfix">
<dt>
<h3>{{name}}</h3></dt>
</dl>
</figcaption>
<figure class="ratioBox">
<div class="js-backstretch content"><img src="{{image}}"/></div>
</figure>
</div>
{{/each}}
</section>
</template>
a simple helper like below
Template.mainEvents.helpers({
"events": function () {
return Events.find({is_deleted:false})
}
})
and lastly a simple iron-route like below:
Router.route('/slider', {
name: 'mainEn',
path: '/slider',
template: 'slider',
layoutTemplate: 'mainLayout',
yieldRegions: {
'indexHeader': {to: 'header'},
'footer': {to: 'footer'}
},
onBeforeAction: function () {
//TAPi18n.setLanguage('en'); // set to english
this.next();
},
action: function () {
// render all templates and regions for this route
this.render();
}
});
Template.mainEvents.rendered = function () {
$('.js-content-slider').slick({
infinite: true,
slidesToShow: 1,
slidesToScroll: 1
});
}
As you can guess i'm trying to generate a slider with the data came from the collection and trying to do it with Slick package.
Template.mainEvents.rendered function works well when roaming between routes. Suppose my slider is in /slider route and i load the meteor app by entering localhost:3000 and then click /slider button. everything works as it's should.
But when try to load the page with localhost:3000/slider route. rendered function triggers before the content fully loaded and slick fails. I manage to work it only by setTimeout function.
How can i get the all content in a template fully loaded and rendered callback in meteor ?
I need $('.selector').load(function () {}) like function.
or any other that can solve this issue.
Thanks in advance.
This is most probably an issue with the collection not having synced yet. You can fix that by adding a waitOn option to your route:
Router.route('/slider', {
name: 'mainEn',
path: '/slider',
template: 'slider',
layoutTemplate: 'mainLayout',
yieldRegions: {
'indexHeader': {to: 'header'},
'footer': {to: 'footer'}
},
onBeforeAction: function () {
//TAPi18n.setLanguage('en'); // set to english
this.next();
},
action: function () {
// render all templates and regions for this route
this.render();
},
waitOn: function () {
return Meteor.subscribe('events');
}
});
Related
I am experiencing a problem when trying to test my portfolio website on my mother’s mobile (Samsung Galaxy JS 3). The images and titles of the projects get loaded onto the index page from JSON with ng-repeat and the links to the information are made from the project IDs with ui-sref. The website loads on the mobile all right and it can direct to the about page, which also uses ui-sref, but it cannot direct to the child pages – it either stays on the main page, or if I force it to go to one of the pages, it displays a blank page with a toggle menu (ng-include header).
It works fine on a Sony Xperia M4, Samsung Galaxy Young, Galaxy A5, my desktop computer (Windows 8.1) and a Mac (not sure about the operating system). I’ve followed the “Hello Solarsystem” tutorial, which also seems to have the same issue when I tried the Plunker version of it on her phone this morning (7th of June).
I have ensured that the site was using the most up to date version after reading ui-sref not working in nested views, I’ve tried adding ui-view to the template that displays the project’s links as is advised on here: Ui-sref not generating clickable links/not working and I am now feeling stuck.
Sorry if my question is a bit long, but I've never had to write one before and I don't want to miss anything.
EDIT: I have now made a plunk with the exact code I'm using for the projects - Plunker and I have now removed ui-router, so it does not load the inner page as a sub page, but at least is viewable in all browsers - the plunk is using ui-router.
The code that I'm thinking has issues is being listed below.
projects.html - view
<div class="container">
<div class="wrapper">
<div class="col-xs-12 col-sm-6 col-md-4 project-block" ng-repeat="project in $ctrl.projects">
<a ui-sref="project({ projectId: project.id })" ui-sref-active="active">
<div class="grid-item university">
<div class="grid-caption">
<img ng-src="{{project.thumb}}" alt="{{project.name}} ({{project.desc}})" id="portfolio-thumb-{{project.id}}" />
<div class="titles">
<div class="grid-projects title">{{project.name}}</div>
<div class="grid-projects desc">{{project.desc}}</div>
</div>
</div>
</div>
</a>
</div>
</div>
</div>
<ui-view></ui-view>
index.html
<body ng-app="myPortfolio">
<div id="wrapper">
<header ng-include="'header.html'"></header>
<div id="page-content-wrapper">
Toggle Menu
<ui-view></ui-view>
<uir-state-vis class="statevis" width="300" height="100"></uir-state-vis>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
</div>
</body>
app.js
var myApp = angular.module('myPortfolio', ['ui.router', 'slick', 'ngAnimate', 'ngRoute', 'ngResource', 'ngTouch', 'ngSanitize', 'ui.bootstrap']);
myApp.config(function ($stateProvider) {
// An array of state definitions
var states = [
{
name: 'about',
url: '/about',
component: 'about'
},
{
name: 'projects',
url: '/projects',
component: 'projects',
// It delegates to the ProjectService to HTTP fetch (async)
// The project component receives this via its `bindings: `
resolve: {
projects: function (ProjectService) {
return ProjectService.getAllProjects();
}
}
},
{
name: 'project',
// This state takes a URL parameter called projectId
url: '/project/{projectId}',
component: 'project',
// This state defines a 'project' resolve
// It delegates to the ProjectService, passing the projectId parameter
resolve: {
project: function (ProjectService, $transition$) {
return ProjectService.getProject($transition$.params().projectId);
}
}
}
]
// Loop over the state definitions and register them
states.forEach(function (state) {
$stateProvider.state(state);
});
});
myApp.config(function ($urlRouterProvider) {
// when there is an empty route, redirect to /index
$urlRouterProvider.when('', '/projects');
});
// preload the async data
myApp.run(function ($http) {
$http.get('data/projects.json', { cache: true });
$http.get('data/info.json', { cache: true });
});
//Make html in JSON file trusted
myApp.filter('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml(text);
};
}]);
projects.js - component
angular.module('myPortfolio').service('ProjectService', function($http) {
var service = {
getAllProjects: function() {
return $http.get('data/projects.json', { cache: true }).then(function(resp) {
return resp.data;
});
},
getProject: function(id) {
function projectMatchesParam(project) {
return project.id === id;
}
return service.getAllProjects().then(function (projects) {
return projects.find(projectMatchesParam)
});
}
}
return service;
})
projects.js - service
angular.module('myPortfolio').service('ProjectService', function($http) {
var service = {
getAllProjects: function() {
return $http.get('data/projects.json', { cache: true }).then(function(resp) {
return resp.data;
});
},
getProject: function(id) {
function projectMatchesParam(project) {
return project.id === id;
}
return service.getAllProjects().then(function (projects) {
return projects.find(projectMatchesParam)
});
}
}
return service;
})
I'am using the version v1.0.0-rc.1 of ui-router and angular 1.6.4 with components.
The is the reduced version of the application routes. Each view is associated with a component. topbar, sidebar and pageContent are all components.
The way the code is below the main view is not injected with the pageContent component and there are no errors or warnings. But topbar and sidebar are injected.
Plunker link to reproduce it: https://plnkr.co/edit/NedgoYEjkAxaRXRJHSoL?p=preview
// Application routes
$stateProvider
.state('root', {
url: '',
abstract: true,
views: {
topbar: 'topbar',
sidebar: 'sidebar'
}
})
//children of the 'root' route
.state('income', {
url: '/income',
parent: 'root',
views: {
main: 'pageContent'
},
resolve: {
selectedModule: function () {
return 'income';
}
}
})
.state('outcome', {
url: '/outcome',
parent: 'root',
views: {
main: 'pageContent'
},
resolve: {
selectedModule: function () {
return 'outcome';
}
}
});
And this is the index.html
<ui-view name="topbar"></ui-view>
<div id="wrapper">
<ui-view name="sidebar"></ui-view>
<ui-view name="main"></ui-view>
</div>
pageContent.js
(function () {
'use strict';
angular.module('up').component('pageContent', {
templateUrl: 'app/shared-components/page-content/page-content.component.html',
controller: Controller,
bindings: {
selectedModule: '<'
}
});
function Controller() {}
})();
pageContent.html (includes other components)
<div id="page-content-wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-md-12 no-padding">
<sidemenu></sidemenu>
<operations></operations>
<reports></reports>
</div>
</div>
</div>
</div>
Finally if I change the 'root' route to: (with the main view and and empty template url)
.state('root', {
url: '',
abstract: true,
views: {
topbar: 'topbar',
sidebar: 'sidebar',
main: {
templateUrl: ''
}
}
})
then I get WARNING: Tried to load angular more than once, but Everything works, meaning that all views are injected.
Another thing is that if remove jQuery the warning above is not shown. However, I need jQuery to use it with angular.element
Sorry for the long post but I had to give all the details.
Normally <script> tags aren't parsed in templates, this is a simplification in jqLite implementation that exists by design. As explained in this answer, having jQuery loaded before Angular replaces jqLite with jQuery and enables adding <script> nodes dynamically.
The problem seen in the plunk is caused by templateUrl: '' in this piece of code:
.state('root', {
url: '',
abstract: true,
views: {
topbar: 'topbar',
sidebar: 'sidebar',
main: {
templateUrl: ''
}
}
})
This results in loading index page as a template, adding duplicate <script> tags to DOM and evaluating them. If there's no component for main view, it shouldn't be in views.
Regarding the expected behaviour, the view doesn't follow naming scheme, it likely should be:
.state('income', {
url: '/income',
parent: 'root',
views: {
'main#': 'pageContent'
},
...
I have routes set up with iron-router that make sure the page goes to the top of the page:
Router.route('/services', {
name: 'services',
template: 'services',
onAfterAction: function () {
scrollTop();
}
});
function scrollTop() {
window.scroll(0, 0);
}
However, if I am on another route, and I have a link like /services#thisid
it will still take me to the top of the page (not to the portion of the page with the id=thisid).
Is there a way to get around this?
This should address your issue both for this issue and your layout override question.
Router.configure({
layoutTemplate: 'main',
onAfterAction: function(){
console.log('hash', this.params.hash);
if(!this.params.hash){
scrollTop();
}
}
});
Router.route('/services', {
name: 'services',
template: 'services',
});
Router.route('/inquiry', {
name: 'inquiry',
template: 'inquiry',
layoutTemplate: 'alternate'
});
The check for this.params.hash ensures that there is no value for the hash before executing the scrollTop. The layoutTemplate on the inquiry route overrides the layout while still respecting the global onAfterAction.
I wish I can give a more detailed response, but I can't even figure out how to debug this situation.
The situation: When I click on the button, the URL changes for a split second to http://localhost:3000/register. Nothing new gets rendered, the page stays the same as if I didn't click anything. Things I've tried:
Typing in Router.go('/register') in the console works properly
I have tried this with every single route, not just the /register route
I have tried this in both Firefox and Chrome
This is not an issue if I use {{pathFor 'templateName'}} in the template, only when I use Router.go('path')
I have a link in my header to register:
Template.header.events({
'click .register-btn': function(e) {
Router.go('/register');
}
});
And, of course, I have this in my template:
Contact
Here is my entire routing file, router.js:
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound'
});
// Routes
Router.route('/', {
name: 'landingPage', // Main domain routing
layoutTemplate: 'landingLayout',
onBeforeAction: function (pause) {
if (Meteor.user()) {
Router.go('/home');
} else {
this.next();
}
}
});
Router.route('/home', {
name: 'siteHome',
onBeforeAction: function() {
if (this.ready()){
if (!Meteor.loggingIn())
AccountsTemplates.ensureSignedIn.call(this);
}else{
// render the loading template but keep the url in the browser the same
this.render('loading');
this.renderRegions();
}
}
});
Router.route('/weekly_goal/set', {
name: 'setWeeklyGoal'
});
Router.route('/make_entry', {
name: 'makeEntry'
});
// Login and Register Routes
AccountsTemplates.configureRoute('signIn', {
name: 'login',
path: '/login',
template: 'siteLogin',
});
AccountsTemplates.configureRoute('signUp', {
name: 'register',
path: '/register',
template: 'siteRegister',
redirect: '/',
});
When you click a button inside of a form, the default browser behavior is to submit the form which causes another HTTP request and reloads the page. In order to avoid this, your event handler needs to explicitly prevent the default behavior:
Template.header.events({
'click .register-btn': function(e) {
e.preventDefault();
Router.go('/register');
}
});
I would like my Meteor app to use IronRouter for client-side routing.
My routing code looks as follows:
Router.map(function() {
this.route('story', {
path: '/story/:_id',
data: function() {
return Stories.findOne({displayId: +this.params._id});
},
notFound: 'storyNotFound'
});
});
I have 2 templates corresponding to this route:
<template name="story">
Welcome to story: {{this.displayId}}.
</template>
<template name="storyNotFound">
Story not found
</template>
Problem: the 'storyNotFound' template is never rendered, not even when
Stories.findOne({displayId: +this.params._id})
returns undefined.
Instead, the 'story' template is rendered with the text "Welcome to story: ".
What am I missing?
Have you tried replacing notFound: with notFoundTemplate ? The Iron Router example uses notFound but I could only find notFoundTemplate in the source code and that worked for me.
Router.map(function() {
this.route('story', {
path: '/story/:_id',
data: function() {
return Stories.findOne({displayId: +this.params._id});
},
notFoundTemplate: 'storyNotFound'
});
});