I have a small meteor app. Inside there are two templates, one with a selector, and one with simple text. Anytime the selector is changed, I would like to get the second template to re-render. I'm a bit new to this, so any help would be appreciated.
Main.html
<head>
<title>btn-test</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> selector}}
{{> display}}
</body>
<template name="selector">
<select id="carSelector">
<option value="volvo" selected="selected">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
</template>
<template name="display">
{{selectorValue}}
</template>
Main.js
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
Template.selector.events({
'change #carSelector': function(event){
return event.currentTarget.value
}
});
Template.display.helpers({
"selectorValue": function(){
return $('#carSelector').val();
}
});
You need to use a reactive data source to store the selected value, I see you already install ReactiveVar package so let use it:
import { Template } from 'meteor/templating';
import { ReactiveVar } from 'meteor/reactive-var';
import './main.html';
const selectedValue = new ReactiveVar('');
Template.selector.events({
'change #carSelector': function(event){
selectedValue.set(event.currentTarget.value);
}
});
Template.display.helpers({
"selectorValue": function(){
return selectedValue.get();
}
});
Related
I'm loading a grid of data with flow router, but when I view the page the footer always flashes to the top before the data loads. What is the best way to fix this?
Here is the route:
AdminRoutes.route('/dashboard', {
name: 'adminDashboard',
action() {
BlazeLayout.render('AppLayout', {page: 'AdminDashboard'});
}
});
Here is the js file:
import { Template } from 'meteor/templating'
import Stores from '../../../../api/stores/stores.js'
import './AdminDashboard.html'
Template.AdminDashboard.onCreated(function() {
var self = this;
self.autorun(function() {
self.subscribe('stores.names.links');
});
});
Template.AdminDashboard.helpers({
stores: function () {
return Stores.find();
}
});
Here is the html layout file:
<template name='AppLayout'>
{{#if Template.subscriptionsReady}}
{{> Header }}
{{> Template.dynamic template=page}}
{{> Footer }}
{{/if}}
</template>
Here is the dashboard html file:
<template name='AdminDashboard'>
<div class='admin-dashboard-page'>
<section class='stores-grid'>
{{#each stores}}
<div class='store'>
<h2 class='store-name'>{{name}}</h2>
<a href='/admin/dashboard/{{link}}' class='store-button'>Edit</a>
</div>
{{/each}}
</section>
</div>
</template>
I'd try displaying the footer AFTER .stores-grid loads. Create a reactiveVar with a handler that is set to true when your data is loaded and return it's value on a helper, then wrap the footer in an if block on your template.
It would be something like the following...
First create a reactiveVar with a value of false:
Template.AdminDashboard.onCreated(function() {
this.isDataLoaded = new ReactiveVar(false);
var self = this;
self.autorun(function() {
self.subscribe('stores.names.links');
});
});
Set the value to true when the collection is loaded:
Template.AdminDashboard.helpers({
stores: function () {
let data = Stores.find()
if(data) {
Template.Instance().isDataLoaded.set(true)
}
return data ;
},
dataLoaded: function () {
return Template.Instance().isDataLoaded.get();
}
});
Finally, wrap your footer so it's only displayed after data is loaded:
<template name='AppLayout'>
{{#if Template.subscriptionsReady}}
{{> Header }}
{{> Template.dynamic template=page}}
{{#if dataLoaded}}
{{> Footer }}
{{/if}}
{{/if}}
</template>
A simple fix would be to set a minimum height on the div your content will be loaded into, pushing the footer down while the content loads. This may or may not work for you, depending on what the expected height of your content will be.
You could also install a loading screen/animation to hide the footer while the data loads.
I'm having issues finding a way to update the UI AFTER adding to a collection. So in the example below after you click the button and add to the collection an additional input is added to the DOM. All good, but i'd like to find a way to target the new input element and preferably give it focus in addition to CSS. Unfortunately I can't find any info that helps solve this AFTER the DOM's been updated. Any ideas? Thanks
<body>
{{> myTemplate}}
</body>
<template name="myTemplate">
{{#each myCollection}}
<input type="text" value="{{name}}"><br>
{{/each}}
<br>
<button>Click</button><input type="text" value="test" name="testBox">
</template>
test = new Meteor.Collection("test");
if (Meteor.isClient) {
Template.myTemplate.rendered = function()
{
console.log("rendered");
this.$('input').focus()
}
Template.myTemplate.helpers({
'myCollection' : function(){
var testCollection = test.find({});
console.log("helpers");
return testCollection;
}
});
Template.myTemplate.events({
'click button': function(event){
event.preventDefault();
var val = $('[name="testBox"]').val();
console.log("events");
return test.insert({name: val});
}
});
}
Turn what you're adding into a template and call that template's rendered to set the needed css or do whatever transforms are needed.
HTML:
<body>
{{> myTemplate}}
</body>
<template name="item">
<input type="text" value="{{name}}"><br>
</template>
<template name="myTemplate">
{{#each myCollection}}
{{> item this}}
{{/each}}
<br>
<button>Click</button><input type="text" value="test" name="testBox">
</template>
JS:
test = new Meteor.Collection("test");
if (Meteor.isClient) {
Template.myTemplate.onRendered(function() {
console.log("rendered");
this.$('input').focus()
});
Template.myTemplate.helpers({
'myCollection' : function(){
var testCollection = test.find({});
console.log("helpers");
return testCollection;
}
});
Template.myTemplate.events({
'click button': function(event){
event.preventDefault();
var val = $('[name="testBox"]').val();
console.log("events");
test.insert({name: val});
}
});
Template.item.onRendered(function() {
this.$('input').focus();
}
}
On a side note, you should use onRendered instead of rendered as the latter has been deprecated for the former.
Do it inside of your myCollection helper function. Use jquery to target the last input in your template and focus it, add css. Meteor's template helpers are reactive computations based on the DOMs usage of their reactive variables, so it will run each time the DOM updates based on your collection.
One template have button and another template have contains one text field.When ever button clicked that text filed append to the button template at the same time not remove the previous text fields that means the button clicked in 4 times 4 text fields add to the button template.
See the following code :
HTML Code :
<head>
<title>hello</title>
</head>
<body>
<h1>Welcome to Meteor!</h1>
{{> hello}}
</body>
<template name="hello">
Add Text Fields here :
<button>add another text box</button>
</template>
<template name="home">
<input type="text" id="name" />
</template>
JS Code :
if (Meteor.isClient) {
Template.hello.events({
'click button': function () {
//Here to write append logic
}
});
}
I didn't get any idea about this.So please suggest me what to do for this?
Use a client side only collection. Clicking adds a new record. Then in home template you loop on this. new Meteor.Collection(null) the null will tell it that it is local only and won't actually create the collection in the MongoDB.
if (Meteor.isClient) {
var buttonClicks = new Meteor.Collection(null),
clickCounter = 0;
Template.hello.events({
'click button': function () {
buttonClicks.insert({click: clickCounter++});
}
});
Template.home.helpers({
clicks: function () {
return buttonClicks.find({});
}
});
}
<template name="home">
{{#each clicks}}
<input type="text" id="name_{{click}}" />
{{/each}}
</template>
I need some help with meteor. I've template with select options:
<select id="collapseFour" class="form-control collapse">
{{#each examNum}}
<option>{{this}}</option>
{{/each}}
</select>
And I've helper that helps me in creating list of exam numbers:
Template.adminLayout.helpers({
examNum: function() {
var number = [];
for(var i=1;i<=50;i++){
number[i] = i;
}
return number;
}
});
I need to make page redirect to the specified exam page, when I choose one of the options. Like onchange, or href in a tag element. I know that it can be solved with helpers, so tried this:
Template.adminLayout.helpers({
'change [type=select]': function(e,t){
// page redirect
},
});
But it doesn't work. What can choose the problem, any help will be appreciated!
Already solved, just in case if somebody needs. Here is the template:
<select id="collapseFour" name="examNo" class="form-control collapse">
{{#each examNum}}
<option value="{{this}}">{{this}}</option>
{{/each}}
</select>
Js file:
Template.adminLayout.events({
'change #collapseFour': function(event, template) {
no = template.find('[name=examNo]').value;
Router.go('adminExamPage', {no: no});
}
});
And router.js:
this.route('adminExamPage',{
path: '/coordinator/exam/:no',
layoutTemplate: 'adminLayout'
});
I'm starting to learn Meteor.js and, when I've removed autopublish and insecure, my application doesn't work any longer.
I can insert data to database but I can't retrive anything by database.
No errors in console.
This is my code:
client/main.html
<head>
<title>Blog Test</title>
</head>
<body>
<h1>Blog Test</h1>
{{>blog}}
{{>ListBlogs}}
</body>
<template name="blog">
<form class="blog-post" id="blog-post" role="form">
<label id="label-title" class="label-title">Titolo:</label>
<input id="input-title" class="input-title" placeholder="Titolo">
<br>
<label id="label-text" class="label-text">Testo:</label>
<textarea id="input-text" class="input-text" placeholder="Testo"></textarea>
<br>
<button type="submit" class="blog-btm">Submit</button>
</form>
</template>
<template name="ListBlogs">
{{#each posts}}
<h2>{{title}}</h2>
<p>{{text}}</p>
{{/each}}
</template>
client/main.js
Template.blog.events({
'submit #blog-post':function (e){
e.preventDefault();
var title = $('.input-title').val();
var text = $('.input-text').val();
Meteor.call('submitPost',title,text);
}
});
Meteor.subscribe('posts');
server/server.js
Meteor.methods({
'submitPost':function(title, text){
console.log("Titolo: " + title);
console.log("Testo:" + text);
Blogs.insert({title:title, text:text});
}
});
Meteor.publish('posts', function() {
return Blogs.find();
});
lib/blog.js
Blogs = new Meteor.Collection('blogs');
We fixed this in IRC I believe :-)
The problem is that your template ListBlogshas no idea what posts means. You will have to define a helper, so that the {{#each posts}} block gets a meaning.
Fortunately this only requires a very quick fix:
Template.ListBlogs.posts = function(){
return Blogs.find().fetch();
}
Put this in your client/main.js and all posts appear in realtime.
your code it's ok, though you must to try subscribe on collection of this way
Tracker.autorun(function () {
Meteor.subscribe("posts");
});
http://docs.meteor.com/#tracker_autorun
and after that you must to create the helpers, for example...
Template.blog.helpers({
})
Template.ListBlogs.helpers({
posts: function(){
return Posts.find({});
}
})