What I'm trying to do
It seems so simple, but I'm trying to use Meteor's account system with Iron:Router to setup an admin system for a web app. The admin section is the only part of the app with accounts. The admin section is to be at /admin and has a login template, and a data template which should be displayed after the admin logs in.
The code
Base Routers
Router.route('/', {
template: 'user' // Not shown; works fine
});
Router.route('/admin', {
template: 'adminDataPage'
});
Templates
<template name="adminLoginPage">
<div class="cover-wrapper-outer page-admin login">
<div class="cover-wrapper-inner">
<div class="cover-container">
<div class="cover">
<form class="admin-login-form">
<div class="alert alert-danger login-failure">
The username or password is incorrect.
</div>
<input class="form-control username" name="username" type="text" placeholder="Username">
<input class="form-control password" name="password" type="password" placeholder="Password">
<input class="form-control submit" name="submit" type="submit" value="Log in">
</form>
</div>
</div>
</div>
</div>
</template>
<template name="adminDataPage">
<div class="container-fluid page-admin admin-content">
<div class="row">
<div class="col-xs-12">
<div class="scrolling-table">
<table class="table table-striped">
<thead>
<tr>
<th>Year</th>
<th>Make</th>
<th>Model</th>
<th>Engine</th>
</tr>
</thead>
<tbody>
<tr>
<td>Year</td>
<td>Make</td>
<td>Model</td>
<td>Engine</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
<template name="adminLoggingIn">
Logging in...
</template>
(This is incomplete as of right now but it doesn't relate to the problem.)
The issue
The content inside the adminDataPage template is never rendered, no matter what I do. However, anything that is not inside an HTML element is rendered. For example, this would render:
<template name="adminDataPage">
Hello world!
</template>
The world in the following would not render:
<template name="adminDataPage">
Hello <span>world</span>!
</template>
The same goes with the adminLoggingIn template. However, anything in the adminLoginPage template works without an issue.
In essence, the login box is displayed, the client-side Javascript (not shown) takes care of logging in the user, the user sees Logging in..., then the user sees nothing and nothing is shown in the browser's inspector (unless there is un-nested plain text in the adminDataPage template).
What I've tried
If currentUser
<template name="adminDataPage">
{{#if currentUser}}
<div class="container-fluid page-admin admin-content">
<div class="row">
<div class="col-xs-12">
<div class="scrolling-table">
<table class="table table-striped">
<thead>
<tr>
<th>Year</th>
<th>Make</th>
<th>Model</th>
<th>Engine</th>
</tr>
</thead>
<tbody>
<tr>
<td>Year</td>
<td>Make</td>
<td>Model</td>
<td>Engine</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{{else}}
<div class="cover-wrapper-outer page-admin login">
<div class="cover-wrapper-inner">
<div class="cover-container">
<div class="cover">
<form class="admin-login-form">
<div class="alert alert-danger login-failure">
The username or password is incorrect.
</div>
<input class="form-control username" name="username" type="text" placeholder="Username">
<input class="form-control password" name="password" type="password" placeholder="Password">
<input class="form-control submit" name="submit" type="submit" value="Log in">
</form>
</div>
</div>
</div>
</div>
{{/if}}
</template>
This will render the login page when not logged in, as expected. However, once logged in, nothing is rendered. I have also tried integrating {{#if loggingIn}} but to no avail.
Iron:Router hooks
Router.route('/', {
template: 'user'
});
Router.route('/admin', {
template: 'adminDataPage'
});
var requireLogin = function() {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render('adminLoggingIn');
} else {
this.render('adminLoginPage');
}
} else {
this.next();
}
};
Router.onBeforeAction(requireLogin, {only: 'admin'});
This will render the login page if not logged in, as expected, but will not render any content inside HTML elements within the adminLoggingIn or adminLoginPage templates.
Specifications
Meteor v1.1.0.3
Iron:Router v1.0.9
Conclusion
I'm so very confused why Meteor (or Iron:Router) refuses to render certain content in certain contexts. Of course, if anybody has any ideas to help resolve this, please shoot; it'd be much appreciated.
Blaze.render() appears to be at fault here. Using Blaze.render(Template.adminDataPage, document.body) in the console will not render anything but—just like in my problem—plaintext nested directly inside the body element. It will not nest any DOM elements beneath body.
To test, I created a DOM element <div class="test"></div>, nested it within the body of the page, and called Blaze.render(Template.adminDataPage, $('.test')[0]) and it worked. It wasn't formatted correctly, but it worked.
Adding a layout template for Iron:Router to use fixes the issue, like so:
<template name="adminPage">
<div class="test">
{{> yield}}
</div>
</template>
Router.route('/admin', {
name: 'admin',
template: 'adminDataPage',
layoutTemplate: 'adminPage'
});
var requireLogin = function() {
login_dep.depend();
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render('adminLoggingIn');
console.log('Logging in page');
} else {
this.render('adminLoginPage');
console.log('Login page');
}
} else {
this.next();
console.log('Data page');
}
};
Router.onBeforeAction(requireLogin, {only: 'admin'});
Also, nesting the {{#if currentUser}} inside another element works:
<template name="adminPage">
<div class="test">
{{#if currentUser}}
<div class="container-fluid page-admin admin-content">
<div class="row">
<div class="col-xs-12">
<div class="scrolling-table">
<table class="table table-striped">
<thead>
<tr>
<th>Year</th>
<th>Make</th>
<th>Model</th>
<th>Engine</th>
</tr>
</thead>
<tbody>
<tr>
<td>Year</td>
<td>Make</td>
<td>Model</td>
<td>Engine</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{{else}}
<div class="cover-wrapper-outer page-admin login">
<div class="cover-wrapper-inner">
<div class="cover-container">
<div class="cover">
<form class="admin-login-form">
<div class="alert alert-danger login-failure">
The username or password is incorrect.
</div>
<input class="form-control username" name="username" type="text" placeholder="Username">
<input class="form-control password" name="password" type="password" placeholder="Password">
<input class="form-control submit" name="submit" type="submit" value="Log in">
</form>
</div>
</div>
</div>
</div>
{{/if}}
</div>
</template>
Router.route('/admin', {
name: 'admin',
template: 'adminPage'
});
I'm not sure why Blaze refuses to attach certain elements to the body element, but these are some workarounds.
Edit
A better workaround I found is to add an element to which Blaze can prepend the template DOM. Blaze.render(Template.adminDataPage, document.body, $('.render-fix')[0]) where a hidden element with the class of render-fix is placed in the DOM at the time of the initial render will work. In essence:
<template name="adminPage">
{{#if currentUser}}
<div>User logged in stuff</div>
{{else}}
<div>User not logged in stuff</div>
{{/if}}
<div class="render-fix" style="display: none"></div>
</template>
It appears to me that Blaze will not attach any templates to body after the initial render.
Related
I am using drupal and super happy with a live edit field module. However this module has been developed with ajax functionality which works brilliantly but seems to still force a button form wrapper fields. I can use CSS to hide this field which works great but the button field ID and wrapper are generic and takes buttons away from the rest of the site. The button wrapper etc are generated by the Drupal CMS of which edits are way out of my scope of understanding.
<div class="form-actions form-wrapper" id="edit-actions"><input type="submit" id="edit-submit" name="op" value="Save" class="form-submit"></div>
I am trying to hide with
`
div#edit-actions.form-wrapper {
display: none;
}
`
But this is hiding relevant buttons that need to be used elsewhere in the site. Here is some of the container code.
`
<div class="content">
<div class="view view-account-content view-id-account_content view-display-id-block_1 view-dom-id-b611690449f4a19aecf257c830f8b956 jquery-once-1-processed refresh-processed">
<div class="view-content">
<div class="views-form"><form action="/testdev/" method="post" id="views-form-account-content-block-1" accept-charset="UTF-8"><div><input type="hidden" name="form_build_id" value="form-ycIZQs2NnfOiNp4mkOR_11YB656wl-cYbXdlo8Cidwk">
<input type="hidden" name="form_token" value="phM-fFmZ9Y6mbpN-0fXff-cfwKo5JvbVdmhYt40dyNc">
<input type="hidden" name="form_id" value="views_form_account_content_block_1">
<table class="rwcls2 views-table cols-0">
<tbody>
<tr class="odd rwcls views-row-first views-row-last">
<td class="views-field views-field-name">
admin </td>
<td class="noneed views-field-editablefield">
<div><div id="editablefields-field-company" class="editablefield-item editablefield-processed"><div class="field field-name-field-company field-type-list-text field-label-hidden compbutton"><div class="field-items"><div class="field-item even">C2</div></div></div><input class="editablefield-edit editablefield-edit-hover form-submit ajax-processed" type="submit" id="edit-field-company-0-actions-edit" name="edit-field_company-0" value="Edit this field" style="display: none;">Edit this field</div></div> </td>
</tr>
</tbody>
</table>
<div class="form-actions form-wrapper" id="edit-actions"><input type="submit" id="edit-submit" name="op" value="Save" class="form-submit"></div></div></form></div> </div>
</div> </div>
`
Any advise for a new coder would be great. Thanks
I have tried css display none
I have tried adding classes to the field in both form and drupal views
I know my question is kind of stupid one but i am stuck.
I have a table of Contracts, each row have a update button ;
when i click on that button, a modalthat contain the contract edit form is shown.
All work fine but my problem that the modal show the same contract for each row.
For more description this is a screenshot
and this one for the modal
this is my template helper
Template.ContractsList.helpers({
lists: function() {
Meteor.subscribe('listsMethod');
return Contracts.find({});
},
list: function() {
return Contracts.findOne();
}
});
and this is my Template event
Template.ContractsList.events({
'click #editContract'(event) {
$("#showModal").modal("show");
console.log( Contracts.findOne({_id: this._id}) );
},
'click #hideModal'(event) {
$("#showModal").modal("hide");
},
});
and this is my Template
<template name="ContractsList">
<div class="modal fade" id="showModal">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">edit</h4>
</div>
<div class="modal-body">
<div class="card-body">
{{#with list}}
<div class="form-group">
<label class="select">Name</label>
<input type="text" class="form-control" aria-describedby="emailHelp" value={{name}} />
</div>
<div class="form-group">
<label >Package</label>
<div >
<select id="role" name="select" class="form-control" >
<option value="package" selected disabled hidden >{{package}}</option>
<option value="freemium">freemium</option>
<option value="bronze">bronze</option>
<option value="silver">silver</option>
<option value="gold">gold</option>
<option value="platium">platium</option>
</select>
</div>
</div>
{{/with}}
</div>
</div>
<div class="modal-footer">
<Button class="primary" >Create contact</Button>
<Button class="secondary" id="hideModal">Cancel</Button>
</div>
</div>
</div>
</div>
<div class="breadcrumb">
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Package Type</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{{#each lists}}
<tr>
<td>
{{name}}
</td>
<td>
{{package}}
</td>
<td>
<Button class="btn btn-outline-primary" id="editContract"><img src="../../../../../img/icons/addcontact-icon.png" /></Button>
</td>
</tr>
{{/each}}
</tbody>
</table>
</div>
</div>
</template>
in my console log of the template event , i got the data correctly as i want
{_id: "Qu8pTSzLDLGKRNRzd", name: "ilyes", package: "bronze"} {_id:
"w7NDzerxivAjhK3dy", name: "ee", package: "freemium"}
what should i do?
In your click handler set a Session variable (or a reactiveVar) and then use it in your list helper:
Event handler:
'click #editContract'(event) {
$("#showModal").modal("show");
console.log( Contracts.findOne({_id: this._id}) );
Session.set('currentRecordId',this._id);
},
Helper:
list() {
return Contracts.findOne(Session.get('currentRecordId');
}
I'm building an app with Meteor.js, and I've got a form where I would like to be able to allow the user to add a new row to the form when they click a button (button.addExperience). I'm using an HTML Template to populate each row of the form.
How would I have the template (experienceRow) rendered each time the user clicks the button?
See example code below:
<body>
<form>
{{> experienceRow }}
</form>
<button class="addExperience">Add Experience</button>
</body>
<template name="experienceRow">
<div id={{experienceNumber}} class='experienceRow'>
<input type="text" placeholder="name" value="" class="name">
<input type="text" placeholder="address" value="" class="address">
<input type="text" placeholder="phone" value="" class="phone">
</div>
</template>
You will need to use an each block along with a reactive variable. That variable could be a ReactiveVar, a session varaible, a local collection, etc. Here's an example implementation using a ReactiveVar to hold an array of ids:
html
<body>
{{> experienceForm }}
</body>
<template name="experienceForm">
<form>
{{#each experienceIds}}
{{> experienceRow }}
{{/each}}
</form>
<button class="addExperience">Add Experience</button>
</template>
<template name="experienceRow">
<div id={{this}} class='experienceRow'>
<input type="text" placeholder="name" value="" class="name">
<input type="text" placeholder="address" value="" class="address">
<input type="text" placeholder="phone" value="" class="phone">
</div>
</template>
js
Template.experienceForm.onCreated(function() {
this.experienceIds = new ReactiveVar(Random.id());
});
Template.experienceForm.helpers({
experienceIds: function() {
return Template.instance().experienceIds.get();
}
});
Template.experienceForm.events({
'click .addExperience': function(e, template) {
e.preventDefault();
var ids = template.experienceIds.get();
ids.push(Random.id());
template.experienceIds.set(ids);
}
});
Note that you'll need to meteor add reactive-var for this to work.
Recommended reading: scoped reactivity.
I want to create a custom field validation for forms using Meteor. I don't want a packaged solution.
Here is my code so far.
JavaScript:
var errorState = new ReactiveVar;
Template.lottoForm.created = function() {
errorState.set('errors', {});
};
Template.lottoForm.events({
'blur input': function(e, t) {
e.preventDefault();
validate($(this));
}
});
Template.lottoForm.helpers({
errorClass: function (key) {
return errorState.get('errors')[key] ? 'has-error' : '';
}
});
Template.errorMsg.helpers({
errorMessages: function(key) {
return errorState.get('errors');
}
});
function throwError(message) {
errorState.set('errors', message)
return errorState.get('errors');
}
function validate(formField) {
$("input").each(function(index, element){
var fieldValue = $(element).val();
if(fieldValue){
if(isNaN(fieldValue) == true) {
throwError('Not a valid Number');
}
}
});
}
HTML:
<template name="lottoForm">
<form class="playslip form-inline" role="form">
<fieldset>
<div class="form-group {{errorClass 'ball0'}}">
<input type="text" class="input-block form-control" id="ball0" maxlength="2" name="ball0">
</div>
<div class="form-group {{errorClass 'ball1'}}">
<input type="text" class="input-block form-control" id="ball1" maxlength="2" name="ball1">
</div>
<div class="form-group {{errorClass 'ball2'}}">
<input type="text" class="input-block form-control" id="ball2" maxlength="2" name="ball2">
</div>
<div class="form-group {{errorClass 'ball3'}}">
<input type="text" class="input-block form-control" id="ball3" maxlength="2" name="ball3">
</div>
<div class="form-group {{errorClass 'ball4'}}">
<input type="text" class="input-block form-control" id="ball4" maxlength="2" name="ball4">
</div>
<div class="form-group {{errorClass 'ball5'}}">
<input type="text" class="input-block form-control" id="ball5" maxlength="2" name="ball5">
</div>
{{> errorMsg}}
<div class="play-btn">
<button type="submit" value="submit" class="btn btn-primary">Play Syndicate</button>
</div>
</fieldset>
</form>
</template
<template name="errorMsg">
<div class="errorMsg">
{{#if errorMessages}}
<div class="list-errors">
{{#each errorMessages}}
<div class="list-item">{{> fieldError}}</div>
{{/each}}
</div>
{{/if}}
</div>
</template>
<template name="fieldError">
<div class="alert alert-danger" role="alert">
{{errors}}
</div>
</template>
I'm also getting this error message in the console - "Uncaught Error: {{#each}} currently only accepts arrays, cursors or falsey values."
Why do I get this error and how would I implement the custom validation?
Just as the error says, #each template functions must be passed the proper type. Are you sure your errorMessages helper is returning an array? It looks like you are initializing it as a hash.
I am try to when click on Form submit button it navigates to new page with same window dynamically but it is not loading the details but it navigates to that page.I am sending my code also please help me.
Html page
<head>
<title>sample</title>
<link rel="stylesheet" type="text/css" href="style.css" />
</head>
<body>
<div class="container">
{{> header}}
{{> body}}
{{> footer}}
</div>
<div class="row-fluid">
{{render-Router}}
</div>
</body>
<template name="header">
<header>
<div class="header">
<img src="./logo.png" style="height:100px;width:200px;"/>
</div>
</header>
</template>
<template name="body">
<div class="bgbody">
<div align="center">
<form id="login-form" action="/admindetails">
<table>
<p class="admin">Admin Login</p>
<tr>
<td><p for="username">Admin Name</p></td>
<td><input type="text" id="username" name="username" placeholder="UserName"></td>
</tr>
<tr>
<td><p for="password">Password</p></td>
<td><input type="password" id="pwd" name="password" placeholder="password"></td>
</tr>
<td></td><td><input class="btn btn-success" type="submit" value="Log In"></td>
<td><input class="btn btn-capsule" type="button" value="New User"></td>
</table>
</form>
</div>
</div>
</template>
<template name="footer">
<div class="footer">
<div style="padding:20px;">
<div class="footerlinks"><p>AboutUs</p></div>
<div class="footerlinks">|</div>
<div class="footerlinks"><p>ContactUs</p></div>
<div class="copyright"><p>Copyright#Healt_Care</p></div>
</div>
</div>
</template>
Client code:
if (Meteor.isClient) {
Meteor.Router.add({
'/admindetails':'admindetails'
})
Template.body.events
({
'submit #login-form' : function (e,t)
{
/* template data, if any, is available in 'this'*/
if (typeof console !== 'undefined')
console.log("You pressed the button");
e.preventDefault();
/*retrieve the input field values*/
var email = t.find('#username').value
, password = t.find('#pwd').value;
console.log(email);
Meteor.loginWithPassword(email, password, function (err)
{
if (err)
{
console.log(err);
alert(err.reason);
Session.set("loginError", true);
}
else
{
console.log(" Login Success ");
Meteor.Router.to("/admindetails");
}
});
}
});
}
You manage the submit event yourself, so there's no need to set up the action parameter of the form. Setting that parameter causes browser to load target page on submit. Simply remove the parameter and things should work as intended.