When I publish and print <p>{{profile.classes}}</p> I get English,Maths,Science. I would like it to print out with a space after the class English, Maths, Science.
I imagine there is a simple way to do this? I'm using, autoform and simpleschema just incase that's relevant.
Answer from #ThiagoSckianta is almost correct except, you need to replace using regex to replace all occurrences. See this link.
Template.NameOfYourController.helpers({
profileClasses: function () {
return (this.profile && this.profile.classes) ?
this.profile.classes.replace(/,/g, ', ') : '';
}
});
Then, in your html:
<p>{{profileClasses}}</p>
Update:
If profile.classes is an array, then you do 'toString` before calling replace like this
Template.NameOfYourController.helpers({
profileClasses: function () {
var classes = (this.profile && this.profile.classes) ? this.profile.classes.toString() : '';
return classes.replace(/,/g, ', ');
}
});
You should implement a helper function.
Go to the .js file of your page, where the controller is defined, and paste the code below. Remember to substitute the name of your controller.
Template.NameOfYourController.helpers({
profileClasses: function () {
// Avoid a ReferenceError in case your subscription is not ready or the field is not set
return (this.profile && this.profile.classes) ?
this.profile.classes.replace(/,/g, ', ') : '';
}
});
Then, in your .html file, write:
<p>{{profileClasses}}</p>
Another option is to pass a parameter to your helper function:
Template.NameOfYourController.helpers({
formatList: function (list) {
return list ? list.replace(/,/g, ', ') : '';
}
});
Then, in your html:
<p>{{formatList profile.classes}}</p>
The Meteor tutorial is an interesting starting point to learn this.
You can find more details about templates and helpers in this session of the docs
Related
I'm trying to use a helper that should return a Collection specifying a subset of the whole Collection with $in using a reactive array from templates:array.
I have
var tags = new ReactiveArray();
and on some event I change the contents of the array, something along the lines of
tags.pushArray(note.tags);
(or maybe I should use .set()?)
My helper is
Template.editor.helpers({
tagslist() {
return Tags.find({ _id: { $in : tags }});
},
});
But then I get an exception in meteor.js:1010 which looks like this
if (allArgumentsOfTypeString)
console.log.apply(console, [Array.prototype.join.call(arguments, " ")]);
In the stack there is compileValueSelector. This seems to indicate that the compilation of the helper is not content with what it finds.
I've also tried to make tags a template local instance, and adding .get() to the tags in the helper query. But with the same result.
Where should I start looking? Am I using ReactiveArray correctly? Is it possible to do what I want, namely have a reactive query based on an ReactiveArray?
I personally have not used ReactiveArray but I assume this same pattern would work. I stick to using ReactiveVar so here is an example that should get you going in the right direction.
Template.editor.onCreated(function () {
const instance = this;
instance.tags = new ReactiveVar([]);
});
Template.editor.helpers({
tagslist() {
const tags = Template.instance().tags.get();
return Tags.find({ _id: { $in : tags }});
}
});
Template.editor.events({
'click .tag'(event, instance){
const tag = this;
const tags = instance.tags.get();
tags.push(tag);
instance.tags.set(tags);
}
});
Im a Drupal themer and im struggling to modify a module in the way that I need. When something happens I need to run a very simple bit of JavaScript. Ive found the part of the module responsable and the following works:
if (something = something else) {
return array(
'#commands' => array(
// Hacky by works
ajax_command_append('body',
'<script>
alert("Custom Js");
</script>'),
),
);
}
else {
// Do something else
}
However it would be better to call a function that was somewhere else as other modules will want to call it. How can I call a function from another module from within this statement?
You can do it inline, like this
Edit
In my first answer I forgot to wrap the javascript in jQuery(document).ready(function() {})
module
if (something = something else) {
// Inline fixed
drupal_add_js("jQuery(document).ready(function() { alert('Script inline!'); });", "type" => "inline");
// From file
drupal_add_js("myscript.js", "file");
return array(
'#commands' => array(
),
);
}
else {
// Do something else
}
myscript.js
(function() {
alert('Script from file!');
});
// or with jQuery
(function($) {
// Do something with $
})(jQuery);
If you want the javascript code to be in on its own file, do it like that (taken from the examples)
Check out the examples in the documentation
More information on adding javascript to your modules/themes
Adding Javascript to your theme or module
Managing JavaScript in Drupal 7
Edit 2
You can call a javascript function from a module. I would do it like this :
Create a new module that just inject a javascript code. This module should have a lesser weight than any other module so it executes before any of them.
Then call it from any module using Drupal.settings.
Assuming that you created the module, you should save your javascript function into Drupal.settings
(function ($) {
Drupal.settings.exampleModule = {
myFunction : function () {
alert('My example function!');
}
};
}(jQuery));
This will inject that code into settings and will be available to any module which needs to access it.
Your module
if (something = something else) {
// Inline fixed
drupal_add_js("(function($) { Drupal.settings.exampleModule.myFunction(); })(jQuery);", "type" => "inline");
}
else {
// Do something else
}
That's how I would do it. Now, if you need to use the ajax framework you should do something like this (try it, I've never used this framework before, so I'm guessing)
return array(
'#commands' => array(
// Hacky by works
ajax_command_append('body', "(function($) { Drupal.settings.exampleModule.myFunction(); })(jQuery);"),
),
);
How can I reference a template helper from another one? For example...
Template.XXX.helpers({
reusableHelper: function() {
return this.field1 * 25 / 100; //or some other result
},
anotherHelper: function() {
if (this.reusableHelper() > 300) //this does not work
return this.reusableHelper() + ' is greater than 300';
else
return this.reusableHelper() + ' is smaller than 300';
}
});
I have also tried Template.instance().__helpers.reusableHelper - all with no luck.
Alternatively is there a way to define reactive Template instance variables?
XXX is a sub-template that renders multiple times on the same page.
You can but only with global template helpers.
Blaze._globalHelpers.nameOfHelper()
Here is an example calling Iron:Router's pathFor global helper.
Template.ionItem.helpers({
url: function () {
var hash = {};
hash.route = path;
hash.query = this.query;
hash.hash = this.hash;
hash.data = this.data;
var options = new Spacebars.kw(hash);
if (this.url){
return Blaze._globalHelpers.urlFor(options)
} else if( this.path || this.route ) {
return Blaze._globalHelpers.pathFor(options)
}
}
});
EDIT: To your second question. You can call the same template as many times as you like on a page and pass different data attributes directly into it and/or use #each block template wrapper to iterate over data. #each will call a template many times giving it a different data context each time.
#each Example
<template name="listOfPosts">
<ul>
{{#each posts}}
{{>postListItem}} <!--this template will get a different data context each time-->
{{/each}}
</ul>
</template>
Attributes Example
<template name="postDetails">
{{>postHeader title="Hello World" headerType="main" data=someHelper}}
{{>postHeader title="I am a sub" headerType="sub" data=newHelper}}
{{>postBody doc=bodyHelper}}
</template>
This like using of common code, you can make another javascript function which contains the your reusable code and call it from wherever you required.
Like in your code-
function calcField(field){
return field * 25 / 100
}
and in you template helper-
Template.XXX.helpers({
reusableHelper: function() {
return calcField(this.field1);
},
anotherHelper: function() {
if (calcField(this.field1) > 300)
return calcField(this.field1) + ' is greater than 300';
else
return calcField(this.field1) + ' is smaller than 300';
}
});
and
Alternatively is there a way to define reactive Template instance
variables?
you can use Session variables or Reactive variable
Disclaimer: This may not answer your question directly, but it might be helpful for people stuck with a similar use case:
Sometimes it's easy to get locked into the "Meteor way", that standard Javascript rules are forgotten.
Two use cases that sound similar to what you're trying to do:
1. For helpers/events that you can access anywhere on the client-side, simply set a global helper.
Put this in, say, client/helpers.js:
Helpers = {
someFunction: function(params) {
/* Do something here */
}
}
Now Helpers.someFunction() is available to all templates.
If you want to bind the local template instance to it for some reason, again, it's standard JS:
var boundFunction = Helpers.someFunction.bind(this);
2. To create reusable Blaze helpers inside of templates, use Template.registerHelper
For example, this function uses the "numeral" library to format numbers:
Template.registerHelper('numeral', function(context, opt) {
var format = (opt.hash && opt.hash.format) || '0,0.00';
return numeral(context || 0).format(format);
});
You can use this in any template like so:
{{numeral someNumberVariable format='0,0'}}
I found a better solution with collection hooks:
Item = new Mongo.Collection('Items');
Item.helpers({
isAuthor: function(){
return this.authorId == Meteor.userId();
},
color: function(){
if(this.isAuthor())
return 'green';
else
return 'red';
}
});
I then becomes functions of this, usable in both helpers and templates.
i had something similar -- i had 2 helpers in the same template that needed access to the same function. however, that function 1) needed access to a reactive var in the template, and 2) is a filter function, so i couldn't just pass in the data of that reactive var.
i ended up defining the filter function in the templates onCreated() and stored it in a reactive var, so the helpers could access it.
Template.Foo.onCreated(function () {
this.fooData = new ReactiveVar();
function filterFoo(key) {
var foo = Template.instance().fooData.get();
// filter result is based on the key and the foo data
return [true|false];
}
this.filterFoo = new ReactiveVar(filterFoo);
});
Template.Foo.helpers({
helper1: function() {
var filterFn = Template.instance().filterFoo.get();
return CollectionA.getKeys().filter(filterFn);
},
helper2: function() {
var filterFn = Template.instance().filterFoo.get();
return CollectionB.getKeys().filter(filterFn);
},
});
Since this answer is currently missing - I wanted to add an update
In the current meteor version, you should be able to call:
var TEMPLATE_NAME = //the name of your template...
var HELPER_NAME = //the name of your helper...
Template[TEMPLATE_NAME].__helpers[' '+HELPER_NAME]
You should call it like this, if you want to make sure the helper has access to this:
var context = this;
Template[TEMPLATE_NAME].__helpers[' '+HELPER_NAME].call(context,/* args */);
But be careful - this could break in future Meteor versions.
Adding on to Nils' answer, I have been able to access Template level helpers in events using the following code:
'click a#back': (event, instance) ->
if instance.view.template.__helpers[' complete']() && instance.view.template.__helpers[' changed']()
event.preventDefault()
this just came up again at work, and this time we used modules. in this case, we had a number of large, related functions that had to maintain data across calls. i wanted them outside the template file but not totally polluting the Meteor scope. so we made a module (polluting the Meteor scope 1x) and called the functions therein from the template.
lib/FooHelpers.js:
FooHelpers = (function () {
var _foo;
function setupFoo(value) {
_foo = value;
}
function getFoo() {
return _foo;
}
function incFoo() {
_foo++;
}
return {
setupFoo: setupFoo,
getFoo: getFoo,
incFoo: incFoo
}
})();
FooTemplate.js:
Template.FooTemplate.helpers({
testFoo: function() {
FooHelpers.setupFoo(7);
console.log(FooHelpers.getFoo());
FooHelpers.incFoo();
console.log(FooHelpers.getFoo());
}
});
console output is 7, 8.
can we use standard 'InsertCpDialog$initialize()' in our javascript like this , so that i can call other function once it get initializes. I used like below code but it is not working. :(
Type.registerNamespace("Extensions");
Extensions.InsertCpDialog.prototype.initialize = function InsertCpDialog$initialize()
{
alert('hi inside insert');
var p = this.properties;
if(window.document.nameProp == "Name" || window.document.title == "Name") {
var browserName=navigator.appName; // Get the Browser Name
if(browserName=="Microsoft Internet Explorer") // For IE
{
alert('hi inside IE');
//window.onload=init(); // Call init function in IE
}
else
{
if (document.addEventListener) // For Firefox
{
alert('hi inside firefox');
//document.addEventListener("DOMContentLoaded", init(), false); // Call init function in Firefox
}
}
}
}
Original(standard) one is like:
Type.registerNamespace ("Tridion.Cme.Views");
Tridion.Cme.Views.InsertCpDialog = function InsertCpDialog()
{
Type.enableInterface(this, "Tridion.Cme.Views.InsertCpDialog");
this.addInterface("Tridion.Cme.Views.DashboardBase");
};
Tridion.Cme.Views.InsertCpDialog.prototype.initialize = function InsertCpDialog$initialize()
{
}
Edit
hi frank thank you, but already i am using same thing in my code to get the list of componet and template listed on a page under CP tab.
function getbtn() {
//alert('inside getbtn');
var sbtn = document.getElementById ("buttonComponentInsert");
$evt.addEventHandler(sbtn , "click", getListofCPBtnClick);
}
function getListofCPBtnClick(e) {
//code will go here
}
My question is :
I need to get selected Component and template Id from Insert CP window.Earlier i was able to get that by changing the CME extension standard code, but i am not suppose to do that, So first i am trying to initialize the "insert CP window" from my javascript code. I can create event handler for that window, but my question is how to initialize that so that i can call any function once it get initialize. Kindly let me know if i anot clear.
Is your script getting loaded into the dialog?
If not, Albert shows how to do that here: http://albertromkes.com/2012/01/30/tridion-gui-extensions-how-to-load-a-javascript-without-showing-a-gui-element/
He then also shows how to listen to events to accomplish something similar to what you are trying to do.
Ok so I've got my template in its own file named myApp.html. My template code is as follows
<template name="initialInsertion">
<div class="greeting">Hello there, {{first}} {{last}}!</div>
</template>
Now I want to insert this template into the DOM upon clicking a button. I've got my button rendered in the DOM and I have a click event tied to it as follows
Template.chooseWhatToDo.events = {
'click .zaButton':function(){
Meteor.ui.render(function () {
$("body").append(Template.initialInsertion({first: "Alyssa", last: "Hacker"}));
})
}
}
Now obviously the $("body").append part is wrong but returning Template.initialInsertion... doesn't insert that template into the DOM. I've tried putting a partia {{> initialInsertion}}but that just errors out because I dont have first and last set yet... any clues?
Thanks guys
In meteor 1.x
'click .zaButton':function(){
Blaze.renderWithData(Template.someTemplate, {my: "data"}, $("#parrent-node")[0])
}
In meteor 0.8.3
'click .zaButton':function(){
var t = UI.renderWithData(Template.someTemplate, {my: "data"})
UI.insert(t, $(".some-parrent-to-append"))
}
Is first and last going into a Meteor.Collection eventually?
If not, the simplest way I know is to put the data into the session:
Template.chooseWhatToDo.events = {
'click .zaButton' : function () {
Session.set('first', 'Alyssa');
Session.set('last', 'Hacker');
}
}
Then you would define:
Template.initialInsertion.first = function () {
return Session.get('first');
}
Template.initialInsertion.last = function () {
return Session.get('last');
}
Template.initialInsertion.has_name = function () {
return Template.initialInsertion.first() && Template.initialInsertion.last();
}
Finally, adjust your .html template like this:
<template name="initialInsertion">
{{#if has_name}}
<div class="greeting">Hello there, {{first}} {{last}}!</div>
{{/if}}
</template>
This is the exact opposite solution to your question, but it seems like the "Meteor way". (Basically, don't worry about manipulating the DOM yourself, just embrace the sessions, collections and template system.) BTW, I'm still new with Meteor, so if this is not the "Meteor way", someone please let me know :-)
I think you may want to use Meteor.render within your append statement. Also, note that if you are passing data into your Template, then you must wrap Template.initialInsertion in an anonymous function, since that's what Meteor.render expects. I'm doing something similar that seems to be working:
Template.chooseWhatToDo.events = {
'click .zaButton':function(){
$("body").append(Meteor.render(function() {
return Template.initialInsertion({first: "Alyssa", last: "Hacker"})
}));
}
}
Hope this helps!
Many answer here are going to have problems with the new Blaze engine. Here is a pattern that works in Meteor 0.8.0 with Blaze.
//HTML
<body>
{{>mainTemplate}}
</body>
//JS Client Initially
var current = Template.initialTemplate;
var currentDep = new Deps.Dependency;
Template.mainTemplate = function()
{
currentDep.depend();
return current;
};
function setTemplate( newTemplate )
{
current = newTemplate;
currentDep.changed();
};
//Later
setTemplate( Template.someOtherTemplate );
More info in this seccion of Meteor docs