I've recently been trying to work through the Discover Meteor book in an attempt to learn Meteor. In this part we make a 'discuss' button that will route to a page displaying only one component of a list.
A couple of people on the official git site have been talking about how the 'discuss' button is not rendering {{postPagePath this}} even when following the instructions in the book.
I'm wondering if Meteor may have changed its routing format since this book was written.
Here is the git page:
https://github.com/SachaG/Microscope/commit/d0e035e2b175f755b80f3c4201cd5aae5f6885d2
If you've managed to get to that point without any issues before that, then theres no changes that would stop you from being able to complete that section.
Could you share your code of Templates HTML and also your Router js code?
Wasn't quite sure which html so I put 2.
application/layout.html
<template name="layout">
<div class="container">
{{> header}}
<div id="main">
{{> yield}}
</div>
</div>
</template>
header.html
<template name="header">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navigation">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="{{pathFor 'postsList'}}">Microscope</a>
</div>
<div class="collapse navbar-collapse" id="navigation">
<ul class="nav navbar-nav">
{{#if currentUser}}<li>Submit Post</li>{{/if}}
</ul>
<ul class="nav navbar-nav navbar-right">
{{> loginButtons}}
</ul>
</div>
</nav>
</template>
router.js
Router.configure({
layoutTemplate: 'layout',
loadingTemplate: 'loading',
notFoundTemplate: 'notFound',
waitOn: function() { return Meteor.subscribe('posts'); }
});
Router.route('/', {name: 'postsList'});
Router.route('/posts/:_id', {
name: 'postPage',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/posts/:_id/edit', {
name: 'postEdit',
data: function() { return Posts.findOne(this.params._id); }
});
Router.route('/submit', {name: 'postSubmit'});
var requireLogin = function() {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
this.render('accessDenied');
}
} else {
this.next();
}
}
Router.onBeforeAction('dataNotFound', {only: 'postPage'});
Router.onBeforeAction(requireLogin, {only: 'postSubmit'});
Related
Please help with this as I want to customize the navbar and replace the names from default such as application and index etc to my application, home page and etc.
Model Page Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace VidlyMovies.Models
{
public class Customers
{
public int Id { get; set; }
public string Name { get; set; }
}
}
LayoutpageCode
#{
ViewBag.Title = "Random";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2> #Model.Movies.Name</h2>
Controller Page Code
namespace VidlyMovies.Controllers
{
public class MoviesController : Controller
{
// GET: Movies/Random
public ActionResult Random()
{
var movie = new Movies() {Name = "Avengers"};
return View(movie);
}
}
}
OK, assuming this is Bootstrap 3 and your "css" bundle is loading it, their example here could be used. Taking a shot at integrating your code I would try:
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<!-- Wrap your banner, app name etc. in a link back to home page -->
<a href="#Url.Action("Vidly", "Home", new { area = "" })" class="navbar-brand" title="Return to home page.">
<!-- I am using a font awesome icon plus text. You can use a bootstrap glyph or a banner, image, etc. -->
<span><i class="fa fa-home"></i> My App Name</span>
</a>
</div>
<!-- This is where you put your menu items. It will collapse if screen is small. The id is important to link above. -->
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="active">#Html.ActionLink("Vidly", "Vidly", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
<li>#Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
#RenderBody()
<hr />
<footer>
<p>© #DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/bundles/bootstrap")
#RenderSection("scripts", required: false)
</body>
I am loading a series of template from a collection like so.
sidebar/sidebar.html
<template name="Sidebar">
<ul id="slide-out" class="side-nav fixed grey darken-3">
<li class="action-bar">
<span id="add-new" data-target="modal-add" class="modal-trigger"><i class="small material-icons">add</i></span>
<span id="save"><i class="small material-icons">note_add</i></span>
<span id="rename"><i class="small material-icons">mode_edit</i></span>
<span id="delete"><i class="small material-icons">delete</i></span>
<span data-activates="slide-out" id="close" class="button-collapse close "><i class="small material-icons right">reorder</i></span>
</li>
<!-- Load save items-->
{{#if Template.subscriptionsReady}}
{{#each userSaves}}
{{>ListItem}}
{{/each}}
{{else}}
<p>Loading</p>
{{/if}}
</ul>
<i class="material-icons">menu</i>
<!-- Modal form to add new simulator file -->
<!-- Modal Structure -->
<div id="modal-add" class="modal">
<div class="modal-content">
<h4>New Simulator</h4>
{{> quickForm collection=saves id="newSimulator" type="insert" buttonClasses="modal-action modal-close btn waves-effect waves-light" buttonContent="Add"}}
</div>
</div>
</template>
sidebar/Sidebar.js
import { Template } from 'meteor/templating';
import { Saves } from '../../../../api/lists/SimulatorSaves.js';
import { Meteor } from 'meteor/meteor';
import './Sidebar.html';
import './SidebarListItem.js'
Template.Sidebar.onCreated(function() {
var self = this;
self.autorun(() => {
self.subscribe('saves');
})
});
Template.Sidebar.onRendered(function() {
// the "href" attribute of .modal-trigger must specify the modal ID that wants to be triggered
$('.modal-trigger').leanModal({
ending_top: '25%', // Ending top style attribute
});
});
Template.Sidebar.events({
'click .button-collapse': function() {
console.log("here")
$(".button-collapse").sideNav();
}
})
Template.Sidebar.helpers({
saves: () => {
return Saves;
},
userSaves: () => {
return Saves.find({});
}
});
I am trying to get the collection items id from the template so i can use it as a session variable but I am getting undefined.
sidebar/listItem.js
import { Template } from 'meteor/templating';
import { Meteor } from 'meteor/meteor';
import './SidebarListItem.html';
Template.ListItem.events({
'click .file-link': () => {
console.log(this._id);
}
});
sidebar/listitem.html
<template name="ListItem">
<li class="file-link"><i class="material-icons">description</i><span>{{name}}</span></li>
</template>
If any would could help me with this would be great thanks.
You don't have this when using fat arrow ;)
I have abround 6000 documents in my mongo collection, which I need to load up into meteor client upon app startup.
In my routes (located under app/client), I have this:
Router.map(function() {
this.route('home', {
path: '/',
template: 'dashboardWrapper',
waitOn: function() {
return Meteor.subscribe('nasdaq');
},
cache: true
});
});
My dashboardWrapper template looks like this:
<template name="dashboardWrapper">
{{#if Template.subscriptionsReady}}
{{> dashboard}}
{{/if}}
</template>
My dashboard template looks like this:
<template name="dashboard">
<div class="container">
<h2>Priority - 1 Incidents Over Time</h2>
<div class="row">
<div id="yearly-bubble-chart" class="dc-chart">
<strong>Yearly Performance</strong> (radius: fluctuation/index ratio, color: gain/loss)
</div>
</div>
<div class="row">
<div id="gain-loss-chart">
<strong>Days by Gain/Loss</strong>
<a class="reset" href="javascript:gainOrLossChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<div class="clearfix"></div>
</div>
<div id="quarter-chart">
<strong>Quarters</strong>
<a class="reset" href="javascript:quarterChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<div class="clearfix"></div>
</div>
<div id="day-of-week-chart">
<strong>Day of Week</strong>
<a class="reset" href="javascript:dayOfWeekChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<div class="clearfix"></div>
</div>
<div id="fluctuation-chart">
<strong>Days by Fluctuation(%)</strong>
<span class="reset" style="display: none;">range: <span class="filter"></span></span>
<a class="reset" href="javascript:fluctuationChart.filterAll();dc.redrawAll();" style="display: none;">reset</a>
<div class="clearfix"></div>
</div>
</div>
<div class="row">
<div id="monthly-move-chart">
<strong>Monthly Index Abs Move & Volume/500,000 Chart</strong>
<span class="reset" style="display: none;">range: <span class="filter"></span></span>
<a class="reset" href="javascript:moveChart.filterAll();volumeChart.filterAll();dc.redrawAll();"
style="display: none;">reset</a>
<div class="clearfix"></div>
</div>
</div>
<div class="row">
<div id="monthly-volume-chart">
</div>
<p class="muted pull-right" style="margin-right: 15px;">select a time range to zoom in</p>
</div>
<div class="row">
<div>
<div class="dc-data-count">
<span class="filter-count"></span> selected out of <span class="total-count"></span> records | Reset All
</div>
</div>
<table class="table table-hover dc-data-table">
</table>
</div>
<div class="clearfix"></div>
</div>
</template>
The relevant part of Meteor.client looks like this:
if (Meteor.isClient) {
var ndx,data;
Template.dashboardWrapper.onCreated( function() {
var template = this;
template.subscribe("nasdaq");
});
Template.dashboard.onCreated( function() {
data = Nasdaq.find().fetch();
ndx = crossfilter(data);
});
Template.dashboard.onRendered(function(){
var self = this;
self.subscribe("nasdaq", function() {
self.autorun(function() {
data = Nasdaq.find().fetch();
});
});
What I expect from this, is for the dashboard template to wait until all the data from the Nasdaq collection loads up.
What happens is absolutely nothing - no data and no errors.
If I remove ironRounter all together, and refresh, I can get a couple of dozen records (out of 6000 total).
Is there a way reliably force the app to wait until every single document loads up?
Try subscribe right before load the current template, may be it will work.
Router.route('/dashboardWrapper/:_id', {
name: 'dashboardWrapper',
waitOn: function () {
return [
Meteor.subscribe('nasdaq')
];
},
data: function () {
return Nasdaq.findOne(this.params._id);
}
});
The code below suppose to get the text insdie of the list, so if task1 is clicked then an alert should say task1, if task2 is clicked, then the alert says text2...
But when I click on any of the link, no alert shows up let along its message. I must be doing something wrong. Pleas help. Thanks
Template.mainMenu.helpers({
menuItems: [
{menuItem: "task1"},
{menuItem: "task2"},
{menuItem: "task3"},
{menuItem: "task4"},
{menuItem: "task5"},
{menuItem: "task6"},
{menuItem: "task7"}
]
});
Template.mainMenu.events({
'click .menuItem': function(){
alert(event.target.menuItem.value);
}
});
<template name="mainMenu">
<div class="container">
<div class="row">
<section class="col-xs-12">
<div class="list-group">
{{#each menuItems}}
<a href="#" class="list-group-item menuItem">
<img src="/abc.png">
{{menuItem}} <span class="badge">></span>
</a>
{{/each}}
</div>
</section>
</div>
</div>
</template>
You haven't defined argument (event) of function.
Below example will help you understand that your code was throwing uncaught errors.
Template.mainMenu.events({
'click .menuItem': function(event){
try{
alert(event.target.menuItem.value);
} catch (e){
alert(e)
}
}
});
Update
Add data-value={{menuItem}} to link and then try to get this value using jQuery:
<template name="mainMenu">
<div class="container">
<div class="row">
<section class="col-xs-12">
<div class="list-group">
{{#each menuItems}}
<a href="#" class="list-group-item menuItem" data-value={{menuItem}}>
<img src="/abc.png">
{{menuItem}} <span class="badge">></span>
</a>
{{/each}}
</div>
</section>
</div>
</div>
</template>
Template.mainMenu.events({
'click .menuItem': function(event){
try{
alert($(event.currentTarget).data('value'));
} catch (e){
alert(e)
}
}
});
I've created a list group that is wrapped in an afModal template. Inside the each list group item, there are glyphicon buttons that trigger different events.
<div class="list-group">
{{#each getRuns}}
{{#afModal title="Edit Run" class="list-group-item" collection="Runs" operation="update" doc=_id formId="editRunForm"}}
{{#if active}}
<span class="glyphicon glyphicon-pause pull-right" name="pause" id="{{_id}}"></span>
<span class="badge">Active</span>
{{else}}
<span class="glyphicon glyphicon-remove pull-right" name="delete" id="{{_id}}"></span>
<span class="glyphicon glyphicon-play pull-right" name="activate" id="{{_id}}"></span>
{{/if}}
<h3>{{name}}</h3>
<p class="list-group-item-text">Assembly: {{assemblyName}}</p>
<p class="list-group-item-text">Quantity: {{quantity}}</p>
<p class="list-group-item-text">Progress: {{completedSteps}} of {{totalSteps}} steps completed</p>
{{/afModal}}
{{/each}}
</div
Here are the glyphicon click events
'click [name="delete"]': function(event) {
if (confirmDelete()) {
Meteor.call('removeRun', event.target.id, function(error) {
if (error) {
alert(error);
}
});
}
event.preventDefault();
},
'click [name="activate"]': function(event) {
Meteor.call('activateRun', event.target.id);
event.preventDefault();
},
'click [name="pause"]': function(event) {
Meteor.call('pauseRun', event.target.id);
event.preventDefault();
}
When the glyphicon click events are triggered, it also triggers the overlying afModal button. I've tried including event.stopPropagation(), event.stopImmediatePropagation(), and event.preventDefault() in the glyphicon click event to prevent the afModal from popping up but none of them work.
Previously, the list group was wrapped in link elements and looked something like this.
<div class="list-group">
{{#each getRuns}}
<a href="{{pathFor 'editRun'}}" class="list-group-item">
{{#if active}}
<span class="glyphicon glyphicon-pause pull-right" name="pause" id="{{_id}}"></span>
<span class="badge">Active</span>
{{else}}
<span class="glyphicon glyphicon-remove pull-right" name="delete" id="{{_id}}"></span>
<span class="glyphicon glyphicon-play pull-right" name="activate" id="{{_id}}"></span>
{{/if}}
<h3>{{name}}</h3>
<p class="list-group-item-text">Assembly: {{assemblyName}}</p>
<p class="list-group-item-text">Quantity: {{quantity}}</p>
<p class="list-group-item-text">Progress: {{completedSteps}} of {{totalSteps}} steps completed</p>
</a>
{{/each}}
</div>
Using the "a" elements (and using the same glyphicon click event handlers) I was able to stop the "a" element from triggering. I'd really like to use the afModal template if possible but can't have the modal popping up every time one of the glpyhicons is clicked. Any advice?
The key is calling the preventDefault before everything else, therefore changing
'click [name="pause"]': function(event) {
Meteor.call('pauseRun', event.target.id);
event.preventDefault();
}
to
'click [name="pause"]': function(event) {
event.preventDefault();
Meteor.call('pauseRun', event.target.id);
}
should work. Of course you should do that for all your event handlers.