Where to run jQuery after ember template renders? - ember.js

With Views deprecated, I'm having trouble discerning where to run jQuery after a Template has rendered.
I have a simple index Template for a foods resource (templates/foods/index.hbs), and wish to run the following jQuery after index.hbs renders:
this.$('[data-toggle="tooltip"]').tooltip();
I know one can create a Component that then has a didInsertElement hook, but I'm not clear on how I'd route to the Component if I did this. Would I then "double dip" by having my apps/templates/foods/index.hbs Template simply call the new Component, which would have its own template that would be the original index.hbs Template?
I'm sure I'm missing something simple here. Anyone care to point me in the right direction?

You can call jQuery in route:
export default Ember.Route.extend({
actions: {
didTransition() {
Ember.run.next(this, 'initTooltip');
}
},
initTooltip() {
Ember.$('[data-toggle="tooltip"]').tooltip();
}
});
You can also create component and use it inside your template like this:
{{tooltip-wrapper}}
<!-- HTML here -->
{{/tooltip-wrapper}}
And call jQuery code in didInsertElement of tooltip-wrapper component.

Related

Ember can't find my template when using the renderTemplate hook

I can’t figure out why Ember can’t find and render the template specified in my renderTemplate hook override. I have the following route configuration as per router.js:
this.route('posts', function() {
this.route('history', function() {
this.route('new', { path: '/new/:id'});
});
});
I’m also making use of my history index route. Therefore, my history.hbs is just an outlet, and all my templating for this route is actually housed in index.hbs. This way, I can render my new.hbs template on its own page.
In new.hbs, I’d like to render an outlet, in addition to some other content. To handle this, I attempted to override the renderTemplate hook in routes/new.js, like this:
renderTemplate() {
this.render('posts/history/test', {
into: 'new',
outlet: 'test',
});
}
I created the new template under templates/posts/history:test.hbs`. File structure for my templates folder looks like this:
templates > posts > history > new.hbs, test.hbs
Finally, in new.hbs, I added my outlet for this new template:
{{outlet 'test'}}
When I navigate to my new route, I get the following error:
Assertion Failed: You attempted to render into ’new' but it was not found. Anyone know how I can get past this?
I believe you can only render into an ancestor route.

Dynamic add/remove a component to the page via action

I am creating a FlashCard app and I would like to dynamically insert a component with property into the view via the action inside the route. See screenshot below,
Click "Add Card" button
Dynamically create a card-editor component in the view
I think one possible way to achieve this is to add a conditional handlebar block inside the view and render the component based on the property state; however, I wish to keep my view as clean as possible and think it could be better if I can dynamically render a component to the view only when the action is triggered.
My solution
<div style="margin-left: 200px;">
{{#if cardEditor}}
{{app/card-editor}}
{{/if}}
</div>
In view's controller
export default Ember.Controller.extend({
cardEditor: false,
actions: {
addNewCardEditor() {
this.set('cardEditor', true));
}
}
});
What I have tried
Based on the answer How to programatically add component via controller action in ember 2.x, but it does not work for me. I get an error,
ember.debug.js:41417 Uncaught Error: Cannot instantiate a component without a renderer. Please ensure that you are creating <(subclass of Ember.Component):ember604> with a proper container/registry.
Inside the view HTML,
{{app/side-bar
addNewCardPressed='addNewCardEditor'
}}
Inside the view route,
import Ember from 'ember';
import CardEditorComponent from '../../components/app/card-editor';
export default Ember.Route.extend({
actions: {
addNewCardEditor() {
CardEditorComponent.create().appendTo($('body'));
}
}
});
Inside the component JS,
actions: {
addNewCardPressed() {
this.sendAction('addNewCardPressed');
}
}
Question
So my question is how can I use the action inside the routes/home/index.js to render the component to the view.
The View HTML,
{{side-bar
addNewCardPressed='addNewCardEditor'
}}
The Index Page route,
import Ember from 'ember';
export default Ember.Route.extend({
actions: {
addNewCardEditor(newCard){}
}
});
What should I put inside the addNewCardEditor function to generate a component in the view on the fly?
Thanks for your time.
in the global.js of your EmberCLI application:
export function initialize(application) {
window.EmberApp = application; // or window.Whatever
}
Where you want to create dynamically your component, even though it might look like a hack, there might be cleaner way to do it without relying on EmberCLI variables.
"App" below is the namespace of your global EmberCLI application that you define in application.js.
var component = App.CardEditorComponent.extend({
renderer: window.EmberApp.__container__.lookup('renderer:-dom'),
}).create();
Ember.setOwner(component , window.EmberApp);
component.append();

Ember re render component

I have a component with a jquery menu that transforms the DOM. I need to re render the component for initiate the structure again. The jquery menu doesn't work dinamically, so I need to re render the component.
//Parent Component hbs
<div id="container">
{{menu-jquery model=model}}
</div>
//Parent Component js
export default Ember.Component.extend({
refreshMenuData(){
callToServer()// ajax call
updateModel()// generate model from ajax response
-> //how to delete and create menu component? or re render menu component?
}
}
Thanks
A component has a function called rerenderthat you can call to force a rerender of the component. Although, I might recommend a better approach. Upon resolution of the promise that fetches your server data, manually destroy the jquery plugin and then reinit said plugin.
I found a workaround putting the component inside a conditional block. I set loading in false before the server call and true after data parsing.
{{#if loading}}
// show loading message
{{else}}
{{menu-jquery model=model}}
{{/if}}
This force the menu component to re render.
Your question is not quite clear. I am assuming that, you will be using jquery ajax for server calls inside the component. In Ember.Component, you have to use .on("didInsertElement") which works similarly as that of jQuery(document).ready(). So your component will look something like this
export default Ember.Component.extend({
_onReady: function() {
refreshMenuData();
//whatever jquery code you want to execute here
}.on('didInsertElement')
})
If you can provide your example in Ember Twiddle or JSBin, I can help you better.

How to add a carousel to an ember site

I would like to add a carousel, preferably caroufredsel http://caroufredsel.dev7studios.com/, to a few templates/routes on an ember site. I was wondering what the best way to do that would be?
All that is needed to fire the items that you want to slide is the following jQuery function:
$(document).ready(function() {
$("#foo1").carouFredSel();
});
Where do you think the best place in the app to put this is?
The best place it to create a custom View for the template that will have the carousel. Then use the didInsertElement hook to initialize the widget once the markup for the carousel once it is in the document. You can also use the willDestroyElement hook to tear down the carousel before the markup is removed from the document.
So, say that you have a /carousel route, and then you have this as your 'carousel' template.
<div id="foo1">
<!-- Other carousel markup goes here-->
</div>
Then you'd create a View like this.
App.CarouselView = Ember.View.extend({
didInsertElement : function(){
$("#foo1").carousel();
},
willDestroyElement : function(){
$("#foo1").trigger("destroy");
}
});

inline javascript within handlebars template

Is there no way to have an inline script within a Handlebars template?
<script type="text/x-handlebars">
I'm a row of type "foo"
<script type="text/javascript">alert('hi');</script>
</script>
When the above template renders, the inline script is removed.
What I am trying to do is include the disqus widget on a page. The widget is basically some markup + disqus script.
The widget is to be included within a sub-view of my app. The subview is not visible by default but is displayed as per some logic in my Ember app code.
​
You'll have to wrap that widget in a custom Ember.View to handle instantiating it and adding it to the DOM, in the wrapper view's didInsertElement. Ember expects, especially inside handlebars templates, to have full control over DOM manipulation, and it does that with a combination of handlebars magic, and Ember.View creation. Once you've defined your customview:
MyApp.DisqusView = Em.View.extend({
didInsertElement: function() {
// create widget and append it to this.$()
}
});
You can use it in your handlebars template:
{{view MyApp.DisqusView}}
Your view should not add Script tags, for safety reasons, but should rather execute any JS directly to insert the widget.