I am using materialize css library and it says
Collapsible elements only need initialization if they are added dynamically
And i add some elements dynamically. So after the view is rendered i should run this function:
$('.collapsible').collapsible({
accordion : false
});
In setupController function i make some requests and after every request finished i setup the controller. When controller gets the model and after the view is rendered with the new model data i should run a function to initialize the ui elments
You have to setup an ember.js component for your accordion and use the didInsertElement hook:
export default Ember.Component.extend({
classNames: ['.collapsible'],
didInsertElement() {
Ember.run.scheduleOnce('afterRender', this, function() {
this.$().collapsible({
accordion: false
});
});
},
});
Related
I want to execute JavaScript when all content (e.g. images) has been loaded in my Ember application.
I already tried using didInsertElement() and didRender() hooks, but it looks like they do not wait for background images to load.
Here's what my component's code snippet looks like:
export default Ember.Component.extend({
didInsertElement() {
this._super(...arguments);
Ember.run.scheduleOnce('afterRender', this, function() {
var home =$('#main-outlet')[0];
home.className += " homePage";
startTimer(5);
});
},
});
Any solution or an alternative approach for this?
Ember does not have an event that is equivalent to onload.
However, regarding an alternate approach, you could leverage Ember’s alias for jQuery, in combination with the didInsertElement hook within your component, to achieve the order of execution that you are looking for. Try this:
export default Ember.Component.extend({
didInsertElement() {
Ember.$(window).on('load', this.executeCssAnimations);
},
executeCssAnimations() {
// your CSS and animation logic would go here
Ember.$('.big-background')
.text('NOW READY FOR CSS and ANIMATION UPDATES.')
.css('color', 'yellow');
},
willDestroyElement(...args) {
this._super(...args);
Ember.$(window).off('load', 'window', this.executeCssAnimations);
},
});
The willDestroyElement hook has been included as well, to show proper teardown and removal of the load event listener from window.
I’ve created an Ember Twiddle example to demonstrate this for you.
I have next structure:
builder.hbs (template)
builder.js (route)
builder.js (controller)
I want to execute some jQuery code when template will be rendered. I found old solutions with View and didInsertElement, but I don't have View in this case. So, is it possible to execute jQuery code from route or controller?
jQuery code:
this.$("#filtersMenu").fixedsticky();
You have didInsertElement on the view of the controller. If say you have IndexController then in views/index.js you would have:
export default Ember.View.extend({
didInsertElement: function(){
this.$('#filtersMenu').fixedsticky();
this._super();
}
});
JSFiddle: http://emberjs.jsbin.com/kegere/1/edit?html,js,output besides that globally jQuery is always on Ember.$:
Ember.$('#filtersMenu').fixedsticky();
That said you should consider putting this into a component that's entirely responsible for rendering it.
I'm building an Ember app that needs to size a container DIV to be full window height on load of the application, and then run the same resize function again when transitioning to a new route, and then also on window resize.
On a normal site, I'd do this:
var appUI = {
init: function(){
appUI.sizeContainer();
},
sizeContainer: function(){
var winHeight = jQuery(window).height();
jQuery('#container').height(winHeight);
},
onResize: function() {
appUI.sizeContainer();
}
}
jQuery(document).ready(function($){
appUI.init();
jQuery(window).resize(function(){
appUI.onResize();
});
});
But obviously this won't work in Ember.
This can't be a component, because the #container DIV wraps the entire current view. But with Ember moving away from views, how should I do this?
The only way I came up with was to use a view, and hook onto didInsertElement, but I couldn't figure out how can I do it without having to create a view.js file for every route, that contains the same resize code? And how about the resize event? I thought the application view didInsertElement might work for this, but it only runs once on load.
All my route templates basically follow this patten:
{{top-header}}
{{background-image image=backgroundImage}}
{{side-menu session=session menuOpen=menuOpen}}
<div id="container" class="vert-center route-name">
{{partial "_logo"}}
{{some-component}}
</div>
On loading the application and on window resize can be done pretty much the way you described.
One easy way is to override the renderTemplate hook inside the ApplicationRoute. Within this hook, you can render your application template and then initialize the resize listener on the window object:
// handles on document load and on window change events
App.ApplicationRoute = Ember.Route.extend({
renderTemplate: function(controller, model) {
this.render('application'); // render the application template
appUI.init(); // call the init event on application load
Ember.$(window).resize(function() { // setup resize listener on the window object that will be called when window resizes
appUI.onResize();
});
}
});
As far as resizing each time a route loads, you could implement a generic Ember.Route, let's call it ResizableRoute for example, that calls the appUI.resize() after its template is rendered. This can again be achieved with overriding the renderTemplate hook.
// calls onResize() each time the current route's template is rendered in the DOM
App.ResizableRoute = Ember.Route.extend({
renderTemplate: function() {
// render the template with the same name as the route (assumes you follow ember naming conventions)
this.render(this.routeName);
// call resize since the route is loaded
appUI.onResize();
}
});
Now you can make any other route extend this ResizableRoute and, every time that route's template is rendered, appUI.onResize() will be called.
App.AnyOtherRoute = App.ResizableRoute.extend({
// do other stuff
});
The reason all the calls are made AFTER the template is rendered is because that way the #container element is definitely inserted in the DOM already and can be grabbed using jQuery.
Here is a running jsFiddle example
EDIT
Instead of overriding the renderTemplate hook, another way you could achieve this is to create a ResizeUIComponent that will perform resizing each time your route is loaded. The flaw is that you have to remember to insert this component into each route's template.
App.ResizeUIComponent = Ember.Component.extend({
didInsertElement: function() {
this.$().hide(); // make the component invisible, probably better to do it with css but this is a quick example
appUI.onResize();
}
});
And add this component to all templates (including application) you want to call onResize() each time they load:
{{top-header}}
{{background-image image=backgroundImage}}
{{side-menu session=session menuOpen=menuOpen}}
<div id="container" class="vert-center route-name">
{{resize-ui}} {{!-- add the invisible resize component as the child of #container to ensure necessary rendering order --}}
{{partial "_logo"}}
{{some-component}}
</div>
And you can add a listener on the window object after the init event of the ApplicationController:
App.ApplicationController = Ember.Controller.extend({
onInit: function() {
Ember.$(window).resize(function() { // setup resize listener on the window object that will be called when window resizes
appUI.onResize();
});
}.on('init');
});
I am using the Hot Towel template by John Papa. I have a html view called nav.html, which contains the header portion of my spa. Within that, i need to display the name of the person that is logged into the system (i have a server side utility class that handles the query).
The following is from the html in the nav.html view for that-
data-bind="text: LoggedInAs"
Here is the viewmodel code (nav.js)-
define(['services/logger'], function (logger) {
var vm = {
activate: activate,
title: 'Nav View'
};
return vm;
//#region Internal Methods
function activate() {
logger.log('Nav View Activated', null, 'Nav', true);
return true;
}
//#endregion
});
My problem is that i am not sure how to do this. i tried adding nav.js to my viewmodels folder, but the javascript does not run. I thought durandal would have picked it up like the other viewmodels. The only difference between the nav.js and the other view models is that the other view models are triggered by clicking on a link (wired through route.mapnav).
What am i missing here? How do i get the javascript to run without a user clicking on a link? When the page loads, I need nav.js to run in order to populate the LoggedInAs data-bind.
Make sure that you are activating your nav view. In the example code you have given in the comment above, it would need to be this:
<header> <!--ko compose: {view: 'nav', activate: true} --><!--/ko--> </header>
I'm Composing this in a view, then trying to call .datepicker() on the result, but nothing happens.
The compose container
<div>
<!--ko compose: { model:'viewmodels/schedule', view: 'views/schedule.html', activate:true} -->
<!--/ko-->
</div>
schedule.html
<div class="schedule-editor">
</div>
And the schedule module
define([], function () {
var vm = {
activate: activate,
};
return vm;
function activate() {
$('.schedule-editor').datepicker();
console.log("activated schedule module");
return true;
}
});
Console logs "activated schedule module", but the datepicker is not created.
If I go to the chrome console and run the jQuery call,
$('.schedule-editor').datepicker(); it brings up the datepicker just fine.
The Durandal docs claim that the activate function is called after the DOM is full composed, so I don't know what else to try.
Like nemesv mentioned you should use viewAttached instead.
define([], function () {
var vm = {
viewAttached: viewAttached,
};
return vm;
function viewAttached(view) {
$(view).find('.schedule-editor').datepicker();
console.log("activated schedule module");
return true;
}
});
Activate happens in the lifecycle before your model has been data-bound to the new view and before the view has been added to the dom. viewAttached happens after the view has been data-bound to your model and attached to the dom.
EDIT
Durandal 2.0 has renamed viewAttached to attached
There is another approach to this that stays true to the declarative UI philosophy that knockout.js and durandal are striving for.
It will allow you to declare the datepicker within the HTML like this:
<div class="schedule-editor" data-bind="
jqueryui: {
widget: 'datepicker',
options: {
// you can set options here as per the jquery ui datepicker docs
}
}">
</div>
Simply include the jquery ui widget bindings found in this gist: https://github.com/SteveSanderson/knockout/wiki/Bindings---jqueryui-widgets
Make sure you include the above javascript after you have loaded jquery, jquery ui and knockout.