Use a helper to set a css class - meteor

I need to make reactive a class inside a const (exported from a module).
export const messageControls = '
<div id="controls"">
<i id="idcont" class="{{starred}}"></i>
</div>
'
This class belongs to an HTML block who's inserted as innerHTML of a createElement.
var newElement = document.createElement('div');
newElement.id = i._id;
newElement.className = "single_message";
newElement.innerHTML = messageControls;
document.getElementById('conversation_details').appendChild(newElement);
The {{helper}} below is not rendering anything :
starred: function () {
return 'bob';
},
<i id="idcont" class="{{starred}}"></i> gives {{starred}} in plain text
<i id="idcont" class=" ' + {{starred}} + ' "></i> breaks all
Any idea?
Update - full Blaze template as requested
<template name="inbox">
<div class="searchmessages">
<input type="text" name="searchmessages" id="searchmessages" placeholder="  any word / any date">
</div>
<div class="row">
<div class="col-xs-4 l-O list_messages">
<div id="gridreceived" class="gridmessages">
{{#each incoming_all}}
<div id="{{_id}}" class="item {{readornot}}">
<div class="item-content">
<div class="task_inlist">
<div class="task_from">
{{{from}}}
</div>
<div class="task_date">
{{initialdate}}
</div>
<div class="task_subject">
{{{subject}}}
</div>
<div class="task_content">
{{{htmlbody}}}
</div>
</div>
</div>
</div>
{{/each}}
</div>
<div class="grid_nomatch">{{grid_noresult}}</div>
</div>
<div id="conversation_details" class="col-xs-8" media="print">
<!--
here are each selected message details
-->
</div>
</div>
</template>

You're trying to inject spacebars template markup directly into the DOM but meteor-blaze wants to use spacebars to build the DOM. It doesn't watch the DOM for arbitrary changes and then make template substitutions inside of it!
You can instead use Meteor's reactivity to automatically insert new items into the DOM for you based on changes to the underlying data. In your case it looks like you're trying to show the details of a message that's been clicked on. You probably have a template event handler already to catch the click. In that template handler you can set a Session variable which indicates which message is currently selected and then use that Session variable inside the helper that renders the message details.
For example:
<template name="inbox">
<div class="searchmessages">
<input type="text" name="searchmessages" id="searchmessages" placeholder="  any word / any date">
</div>
<div class="row">
<div class="col-xs-4 l-O list_messages">
<div id="gridreceived" class="gridmessages">
{{#each incoming_all}}
<div id="{{_id}}" class="item {{readornot}}">
// render summary of each message
</div>
{{/each}}
</div>
<div class="grid_nomatch">{{grid_noresult}}</div>
{{#with selectedMessage}}
<div id="conversation_details" class="col-xs-8" media="print">
// render selected message details
</div>
{{/with}}
</div>
</template>
Your js:
Template.inbox.events({
'click .item'(ev) {
Session.set('selectedMessageId',this._id);
}
});
Template.inbox.helpers({
selectedMessage() {
return Messages.findOne(Session.get('selectedMessageId'));
}
});
Now to your follow-up question about how to reactively style an element. Let's say your message* object has aisStarredboolean key. In the message detail section we've set the data context using{{#with currentMessage}}` so any key of the current message can be used directly in our spacebars template. Where you are displaying the message details you can do:
<div id="controls"">
<i id="idcont" class="{{#if isStarred}}starred{{/if}}"></i>
</div>
Depending on whether or not the message is starred this will render as class="" or class="starred".

Related

How to update document of particular user id

Basically what I want to do is, just update user details.so when
I input user ID all the other details of user are displayed in
textbox. Then I can edit anything.
Below is my js code:
Template.body.onCreated(function() {
this.currentTextBox = new ReactiveVar();
});
Template.body.events({
"keyup .new-task1"(event, instance) {
instance.currentTextBox.set(event.target.value);
}
});
Template.body.helpers({
dbs() {
const instance = Template.instance();
return Dbs.find({'user_id':instance.currentTextBox.get()});
}
});
Template.temp.events({
"submit .sub"(event) {
const target= event.target;
const name1 =target.name.value;
const add1 =add.value;
const r1 = target.r.value;
const const1 = target.const.value;
console.log(doc_id1);
Dbs.update({"user_id" : "pid"},{"name" : "name1","r" : "r1","const"
: "const"});
}
});
Now the problem is I am not able to update the edited field, though the value of edited field is sent to js file from html.anyone help me to solve this issue as I am new to meteor and mongo db.
Html code:
<head>
<title>eg1</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet">
</head>
<body>
<nav class="#e57373 red lighten-2">
<div class="container">
<div class="nav-wrapper">
hello
<ul id="nav-mobile" class="right hide-on-med-and-down">
</ul>
</div>
</div>
</nav>
<div class="row">
<div class="col s2">
<form class="new-task">
<input type="text" name="pid" placeholder="patient_id" class="new-
task1"/>
</form>
</div>
<div class="col s4">
<ul class="collection">
{{#each dbs}}
{{>temp}}
{{/each}}
</ul><br><br>
</div>
</div>
</body>
<template name="temp">
<li class="collection-item">
<form class="sub">
<input type="text" name="user_id" value=" {{user_id}}"/>
<input type="text" name="addd" value=" {{add}}"/>
<input type="text" name="r" value=" {{r}}"/>
<input type="text" name="const" value=" {{const}}"/>
<center><input type="submit" value="Submit" class="waves-effect
#607d8b grey btn"></center>
</form>
</li>
</template>
Welcome to Meteor :)
You have to use $set attribute when you are updating document,
use as below and let me know.
Dbs.update({"user_id" : "pid"},{$set:{"name" : "name1","r" : "r1","const" : "const"}});
For more info on Collection.update Click Here.
Also go through Mongo Update Query example to know how to update a document when you directly use mongo shell.
Remember there are few differences when you directly use Mongo Shell commands and Meteor Collections.

SASS / HandlebarsJS conflicts?

Background: For a project, I am trying to use SASS and Handlebars to create a vote counter that displays a stored value from my database and updates when a user presses the up or down vote buttons.
Are there any known interactions/conflicts that would causes SASS styling to not be applied when used with Handlebars or vice-versa?
For reference, here is the code I have in my HTML that I am working with.
<div id='voteWrapper'>
<script id='voteTile' type="text/x-handlebars-template">
{{#each proTipVote}}
<div class="vote circle">
<div class="increment up" data-id={{_id}}></div>
<div class="increment down" data-id={{_id}}></div>
<div class="count" data-id={{_id}}>{{tipScore}}</div>
</div>
{{/each}}
</script>
</div>

thymeleaf - why can't I pass a date value to controller?

On my HTML5 page I have this code excerpt.
<body>
<script type="text/javascript" >
$(document).ready(function () {
$('#timepicker4').timepicker({
format: 'HH:mm'
});
</script>
// start of page
<div class="header">
<label th:for="timepicker4" th:value="${hourIntervalStart}">Hour Interval Start: </label>
</div>
<div>
<div class="input-group">
<span class="input-group-addon"><i class="fa fa-clock-o"></i></span>
<input name="hourIntervalStart" th:field="*{hourIntervalStart}" id="timepicker4" class="form-control tp_interval1"></input>
</div>
</div>
// rest of page
</body>
The problem is that, though the javascript is correctly displaying the time, the controller prints out (for testing purposes) a null value to the hourIntervalStart attribute.
The appropriate javascript library is correctly loaded and accessible from the browser.
How to correctly pass the the selected value to the controller?

Iron:Router url parameter to modify nested layout

I'm really struggling with this one. If you want to view what I have bludgeoned together, it is all in a repo on GitHub called instructor-oracle. What I would like to do is have the landing page be the layout at ./wbs. Then I would like the search to route to ./wbs/:_wbsCode and populate the sidebar with the appropriate record. I am thinking the router needs to be structured something like...
Router.configure({
layoutTemplate: 'layout'
});
Router.map(function () {
this.route('wbs', {
path: '/wbs'
}, function () {
this.render('wbs-detail', {
path: '/wbs/:_wbsAbbrev',
to: 'wbs-detail',
data: function () {
theOne = Wbs.findOne({abbrev: this.params._wbsAbbrev});
console.log(theOne.abbrev);
return theOne;
}
});
});
...and this would be paried with templates like...
<template name="layout">
<header class="container-fluid">
<nav class="navbar navbar-default" role="navigation">
<div class="navbar-header">
<a class="navbar-brand" href="{{pathFor 'wbs'}}">Instructor Oracle</a>
</div>
<div class="collapse navbar-collapse" id="bs-navbar-collapse">
<form class="navbar-form navbar-left" role="search" id="wbsSearchForm">
<div class="form-group">
<input
class="form-control typeahead"
name="wbsSearch"
id="wbsSearch"
type="text"
placeholder="Search"
autocomplete="on"
spellcheck="off"
autofocus="true"
/>
</div>
<button type="submit" class="btn btn-default">Find</button>
</form>
</div>
</nav>
</header>
<main class="container-fluid">
{{> yield}}
</main>
</template>
<template name="wbs">
<div class="col-sm-3" id="wbsCol">
{{> yield 'wbs-detail'}}
</div>
<div class="col-sm-9" id="timesheetCol">
<iframe src="http://iframeurl.html" id="timesheetFrame"></iframe>
</div>
{{#contentFor 'wbs-detail'}}
<h1>{{abbrev}} <small>{{code}}</small></h1>
{{/contentFor}}
</template>
...and an event handler for the form like this...
Template.layout.events({
// catch submit event for wbs form
'submit': function (event, template) {
// prevent default behavior and stop bubbling
event.preventDefault();
event.stopPropagation();
// store dom element in variable
var inputElement = template.find('input#wbsSearch');
// access value in form and extract abbreviation if found
var abbrev = Wbs.findOne({abbrev: (inputElement.value).toUpperCase()}).abbrev;
// clear input
inputElement.value = "";
// go to the page
Router.go('wbs-edit', {_wbsAbbrev: abbrev});
}
});
I have been trying to sort through this on the iron:router documentation, but right now I am all kinds of lost (obviously). Still, I need this to work to avoid reloads on the main layout template so the iframe does not reload while the sidebar can change along with the matching url so links to specific sidebar content can be bookmarked and shared.
Thank you in advance for your assistance. If I eventually sort all of this out, I am more than happy to contribute to the iron:router documentation so it makes sense for the next pea-brained idiot like myself who happens to need to sort this out.

Can Meteor handle nested views?

I'm learning meteor, and finding all kinds of difficulties dealing with nested subviews. Since the application I want to write is full of them... that looks like a difficulty. I found this on github, as a readme for a Meteor project to try and deal with this problem.
"I've been playing around with Meteor for a couple weeks. The ease of setup and the powerful reactivity makes this something I want to stick with. I was however frustrated by the difficulty of programmatically configuring, instantiating, destroying and nesting subviews."
Is this an issue that can be handled in Meteor (without adding a lot of complicated work arounds) or should I look for a different platform ?
I love nesting templates. I get reliable results. I now program off a library of both templates and helper functions (usually for form elements) that compose html for me. HTML is a byproduct, and the files we call .html are really a javascript DSL.
There are many S.O. issues raised about insertions into sorted lists giving people problems. I haven't had time to look.
My rule of thumb: Meteor is (well) designed from the beginning to do this easily and reliably.
So far the harder thing to solve was when I added an accordion from foundation, and a refresh of the document led to its initial state (being all closed, or one open). I had to put code in that saved the current section, and code to re-assert that in the rendered callback for the template that used it.
Why not write a prototype of the nesting with just a field or two in places, and find what bothers you?
Here is a sample chain. You see all the nested templates. This template itself is running within multiple.
First template: called 'layout', suggested by iron router. Has basic page and menu. Main body is a yield, set by router. On a sample page, a route calls template 'availability'
<template name='availability'>
{{#each myAgents}}
<form class="custom" id="Agent_{{_id}}" action="">
<div id='availability' class="section-container accordion" data-section="accordion">
<section id="services">
<p class="title" data-section-title><a href="#">
Your Info
</a></p>
<div class="content" data-section-content>
{{>services}}
</div>
</section>
<section id="skills">
<p class="title" data-section-title><a href="#">
Skills
</a></p>
<div class="content" data-section-content>
{{>skills}}
</div>
</section>
<section id="sureties">
<p class="title" data-section-title><a href="#">
Sureties
</a></p>
<div class="content" data-section-content>
{{>sureties}}
</div>
</section>
<section id="time">
<p class="title" data-section-title><a href="#">
Time Available
</a></p>
<div class="content" data-section-content>
{{>time}}
</div>
</section>
<section id="schedule1">
<p class="title" data-section-title><a href="#">
Schedule 1
</a></p>
<div class="content" data-section-content>
{{>schedule}}
</div>
</section>
<section id="schedule2">
<p class="title" data-section-title><a href="#">
Schedule 2
</a></p>
<div class="content" data-section-content>
{{>schedule}}
</div>
</section>
<section id="distance">
<p class="title" data-section-title><a href="#">
Distance
</a></p>
<div class="content" data-section-content>
{{>distance}}
</div>
</section>
</div>
</form>
{{/each}}
</template>
sample further nest:
<template name='services'>
{{label_text fname='name' title='Agent Name' placeholder='Formal Name' collection='agent' passthrough='autofocus=autofocus ' }}
{{label_text fname='agentInCharge' title='Agent In Charge' placeholder='Owner' collection='agent' }}
{{label_text fname='phone' title='Phone Number(s)' placeholder='Include Area Code'collection='agent' }}
{{>gps }}
<h4>Not shared:</h4>
{{label_text fname='email' title='Email:' placeholder='you remain anonymous' collection='agent' }}
</template>
and label_text is a helper, learned from the https://github.com/mcrider/azimuth project:
generateField = (options) ->
options.hash.uniqueId = options.hash.fieldName + "_" + Math.random().toString(36).substring(7) if options.hash.template is "wysiwyg"
options.hash.id = options.hash.id or #_id
options.hash.value = options.hash.value or this[options.hash.fname]
# allow for simple params as default
options.hash.title = options.hash.title or options.hash.fname
options.hash.template = options.hash.template or "label_text"
options.hash.placeholder = options.hash.placeholder or options.hash.title
# compatible with old
options.hash.fieldName = options.hash.fieldname or options.hash.fname
options.hash.label = options.hash.label or options.hash.title
# FIXME: Return error if type not valid template
new Handlebars.SafeString(Template[options.hash.template](options.hash))
Handlebars.registerHelper "label_text", (options) ->
options.hash.collection = options.hash.collection or 'generic'
generateField.call this, options
I am fairly new to Meteor, but I found out really soon that I wanted nested views (aka dynamic includes or sub-templates). I'm not sure whether this is what you mean, but here is my solution.
I created the following handlebars helper, that can be used to create sub-templates:
Handlebars.registerHelper('subTemplate', function(container, property, context, options) {
if (container && container.hasOwnProperty(property)) {
var subTemplate = container[property];
if (typeof subTemplate === 'function') {
return new Handlebars.SafeString(subTemplate(context || this));
}
else if (typeof subTemplate === 'string') {
return new Handlebars.SafeString(Template[subTemplate](context || this));
}
}
});
It can be used inside something I call a generic template. For example to create a list:
<template name="item_list">
<ul class="items-list">
{{#each items}}
<li class="listview-item">
{{subTemplate .. 'listItem' this}}
</li>
{{/each}}
</ul>
</template>
Now invoking this generic template requires that a 'listItem' property is present within its context. This can be either a string with the name of the sub-template, or the inline definition of a sub-template. The example below shows both options:
<template name="my_list">
{{! First option, referring to the sub-template by name:}}
<div>
{{#with listData listItem="my_list_item"}}
{{> item_list}}
{{/with}}
</div>
{{! Second option, inlining the sub-template:}}
<div>
{{#with listData}}
{{#assignPartial 'listItem'}}
<span>{{name}}</span>
{{/assignPartial}}
{{> item_list}}
{{/with}}
</div>
</template>
<template name="my_list_item">
<span>{{name}}</span>
</template>
Template.my_list.listData = function() {
return {
items: collections.people.find()
};
};
The second option requires an extra handlebars helper.
Handlebars.registerHelper('assignPartial', function(prop, options) {
this[prop] = options.fn;
return '';
});
I made more of these kinds of useful helpers, at some point I will probably share them on GitHub.

Resources