Given something like a post model with a body attribute, is there a way to get ember to dynamically render {{link-to}}'s within the body attribute?
Example:
// The model
post = {
body: `
{{#link-to "posts.index"}}
<h1>The "{{#link-to}}" is rendered literally!</h1>
{{/link-to}}`
}
// The .hbs file
<div class="container">
{{postBody post.body}}
</div>
// Helper function to avoid escaping the HTML
export function postBody(postBody) {
return Ember.String.htmlSafe(postBody);
}
export default Ember.Helper.helper(postBody);
The only thing I can think to do is enter a static link, which would cause a full page reload.
I think what you are looking for is the compile function. See here for more information. You would call it like this:
Ember.Handlebars.compile(this.get('post.body');
Related
I am new to ember.js and working on an application to highlight text like below:
<div>
<h3 class = "title" {{action "highlight" "title"}}>{{document.title}}</h3>
<div class = "date" {{action "highlight" "date"}}>{{document.date}}</div>
<p class = "content" {{action "highlight" "content"}}>{{document.contents}}
</p>
</div>
I created a function highlight which will get the class name and highlight the search text the user input. This function works fine, but I have to click to trigger this highlight function. Is there any way in ember action helper can trigger this function whenever the div node rendered or automatically triggered?
What you probably need is to implement the hook didInsertElement, this will trigger as soon your component got rendered in the screen.
Example:
import Component from '#ember/component';
export default Component.extend({
didInsertElement() {
this._super(...arguments);
const title = this.element.querySelector('.title');
// do something with the title
},
});
More information about didInsertElement can be found in this guide: https://guides.emberjs.com/v2.18.0/components/the-component-lifecycle/
I don't understand your use-case entirely, but I think actions are not a good choice for your problem. I would recommend reading the ember guides about computed properties. These properties are recomputed everytime an underlying property changes.
highlightedContent: computed('userInput', 'content', function() {
....
//return computedContent;
})
I would also recommend reading the guides about handlebar-helpers. You could write a highlight-helper.
I have the following Meteor template:
<template name="homeBoxTpl">
<div>
Some content
</div>
</template>
I have an event binding so that when a button on the page is clicked it should get the html contents of the template "homeBoxTpl" - how can this be achieved?
What you need is an event handler, and like Chase say you can access the content of meteor templates using jquery, but meteor has its own way. In order to get a copy of the html, you can place a wrapper round the content in the template, then do this:
Template.homeBoxTpl.events({
'click #someButton':function(e,t){
var templateContents = t.$('.wrapperInTemplate').html();
}
})
Here we are using Template.$ wich returns a jQuery object of those same elements.
Take a look into Template.instances for more information
Just to clarify, where is the button? Is it in another template? I assume you only render homeBoxTpl once.
In which case the event handler for the template where your button exists will have no reference to another template instance. There is no global lookup where you can find all rendered instances of a specific Template
You will have to set an unique identifier "id" for it, or some other discerning info such as a class/attribute and find it via old fashioned JS DOM selectors/traversal.
document.getElementById is fastest, but if there are multiple instances of that template, t.firstNode does give you a good starting point for the DOM traversal.
However making your code dependent on a specific DOM layout is bad practice / too much coupling. Is there any reason why the data underlying that Template's HTML content isn't available somewhere else like a session or collection? It would perhaps be more flexible too to access the data not the HTML.
You can use jquery to access what you need. For example, if you have the following template:
<template name="homeBoxTpl">
<div class="content-container">
Some content
</div>
<button id="btn" type="button">Click me</button>
</template>
Then use the following javascript:
Template.homeBoxTpl.events({
'click #btn': function(e) {
e.preventDefault();
var content = $(".content-container").text();
console.log(content); //Result is "Some content"
}
});
I am looking for a way to access model data in a route when using a view to display model attributes.
Example
Template
<h2>New post</h2>
<form {{action save model on="submit"}}>
<label>Title</label>
{{input type="text" value=title placeholder="title" id="title"}}
<label>Text</label>
{{view "tinymce" value=text }}
<button>Post</button>
</form>
View Template
<textarea id="tinymce">
</textarea>
View
export default Ember.View.extend({
templateName: 'views/tinymce-textarea',
didInsertElement: function() {
tinymce.EditorManager.execCommand('mceRemoveEditor',true, 'tinymce');
tinymce.EditorManager.execCommand('mceAddEditor',true, 'tinymce');
}
});
Router
export default Ember.Route.extend({
....
actions : {
save : function(model) {
if (!model.get('title').trim() || !model.get('text').trim()) {
return;
}
model.save().then(this.onSuccessfulSave.bind(this), this.onFailedSave.bind(this));
}
}
});
Now, obviously this doesn't work, since model.text is never bound in the view, like it would be if I were to use the textarea template helper:
{{textarea value=text placeholder="text" id="text"}}
But this is just one of many (many) ways I have tried to get this to work, and I am at a complete loss as how one would access model attributes in the route when using a view. And it does seem like a pretty common usecase to me too.
I have failed to find information regarding this on SO or anywhere else, so if anyone is able to help me, thanks in advance! / AS.
So one of the main things that you're missing out is binding the view to the controller. This is actually really straight forward to do, but without it Ember doesn't know that it should propagate changes between the two. The first thing I would do is this:
{{view "tinymce" valueBinding="text" }}
This says that the views value will be binded to the controller's text value. Whenever view's value is updated, it will propogate to the controller and vice versa.
The next item to take care of is actually binding the value in the view. All you need to do is tell the input to bind it's value to the view's value. This can be done like this
{{textarea value="view.value" placeholder="text" id="text"}}
Try this out, and you can use this jsbin that I created as an example:
http://emberjs.jsbin.com/qanudu/26/
If you have any other questions just let me know, but this should solve your issues!
I am getting some data from server and in my controller I am trying to display that in list format. What I want to do is to allow the user to click on any item of that list and call an action behind it. Here is my js code.
for(var index in posts) {
if (posts.hasOwnProperty(index)) {
console.log(1);
var attr = posts[index];
//console.log(attr);
/*$("ul#previous_recipients").append('<li class="list-group-item"><label>'+attr.name+'' +
'</label><a href="javascript:void(0)" class="close g-green" {{action "aa"}}>Add</a></li>');*/
$("ul#previous_recipients").append(Ember.Handlebars.compile('<li class="list-group-item"><label>{{attr.name}} </label>Add</li>'));
}
}
How to call action on it? {{action "test"}} is not being called.
You have to compile the handlebars template and define the test action inside actions hash in the same controller.
$("ul#previous_recipients").append(Ember.Handlebars.compile('
<li class="list-group-item"><label>{{attr.name}} </label>
Add</li>
'));
You have to move this html code from controller to a handlebars file,that will be good.
What you need to do is create an ember view and give it a
templateName
property which will contain your html and handlebars expression. Alternately, you could, inside the view say
defaultTemplate: Em.Handlebars.compile(/*your handlebars and html markup here*/)
using Jquery to do things like this is not the ember way of doing things.
Currently, if we define our view as {{#view App.myView}}, ember/handlebars will wrap the view element inside a <div id="ember-1234" class='ember-view'>.
Is there a way to stop this?
You probably want to set tagName as ''.
App.MyView = Em.View.extend({
tagName: ''
});
At least it stops wrapping inner contents.
If you want to customize view element's id, you can use:
{{#view App.myView id="my-id"}}
I usually think my views as wrapper. For example, if the initial given html code is :
<div class="item"><p>my stuff></p></div>
Then I create a view with a tagName property as "div" (which is default), and classNames property as "item". This will render, with proper handlebars template :
{#view App.myView}
<p>my stuff></p>
{/view}
-> render as
<div id="ember-1234" class="ember-view item">
<p>my stuff></p>
</div>
Then if you need to have your proper ID on this div, you could define the "elementId" property on your view class (before create()). (#see source code)
I assume you are talking about the 'ember-view' class which is not customizable (element type being customizable thanks to the tagName attribute...).
Actually, Ember later uses this class to register (once!) an event listener on the document in order to dispatch events to the JS view.
I don't mind it would be that simpler to avoid using this class. There would have to find another way to select all ember's controlled element, but I have no idea how.
See source, # line 117.
If I understand you correctly you want to achieve something like jQuery's replaceWith? You can use this in Ember.js when my Pull Request gets merged: https://github.com/emberjs/ember.js/pull/574.
Also have a look at Create Ember View from a jQuery object