Ember app kit Application view didInsertElement fired only once - javascript

Hi I use Ember app kit and I need to fire a didInsertElement every time I changed route(child view - view in outlet). I need something like global app DOM ready event.
I found mavilein's solution but it doesnt work.
Here is my app/views/application.js:
export default Ember.View.extend({
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent : function(){
// implement this hook in your own subclasses and run your jQuery logic there
console.log("FIREEEEE");
}
});
When I run the app it fires the didInsertElement, but when I change route(click on link) it doesnt trigger the application view didInsertElement event.
I know that application view doesnt change, but I need something what fires every time I change child view. Or am I ruining the architecture and do it other way?
Thanks for any help.

Hey #petkopalko from what you said in the comments you want to use Holder.js for placeholder images and like you said you need to execute the Holder.run() function because of how holder.js works. What you can do is add Holder.run() to each view that needs it in the didInsertElement hook but that is not what you want to do and that could get tiresome.
Now from your code above, with Ember App Kit (EAK) and the resolver i think what you are actually doing by saying:
export default Ember.View.extend({...
from within app/views/application.js is actually exporting a View associated with the ApplicationView which is why is will only execute once because the Application View gets insert on page load.
I was doing a little hacking and what seems to work is that you have to reopen Embers view class (object) and add the holder.run in the didInsertElement hook. What seems to work best from me from within EAK with reopening Ember base classes is do it in the app.js file.
That would look like this in app.js file:
Ember.View.reopen({
didInsertElement: function(){
Ember.run.next(function(){
Holder.run();
}
}
});
And it seems to work with just ember.run
Ember.View.reopen({
didInsertElement: function(){
Ember.run(function(){
Holder.run();
}
}
});
And if you want you can keep all you code from before just place it in app.js
Ember.View.reopen({
didInsertElement : function(){
this._super();
Ember.run.scheduleOnce('afterRender', this, this.afterRenderEvent);
},
afterRenderEvent : function(){
// implement this hook in your own subclasses and run your jQuery logic there
console.log("FIREEEEE");
//You can place the holder.run() function here and not in views
Holder.run();
}
});
If you dont place Holder.run() in your afterRenderEvent function in the reopen View. You will have to place it in the views afterRenderEvent function that you seems to want.
SomeView = Ember.View.extend({
afterRenderEvent: function() {
this._super();
Holder.run();
}
});
Not sure of side effects with these approaches but you can explore them after implementing. So you have a few options here: Happy coding.
Attached here is a jsbin that seems to illustrate the behavior that i think you are looking for:
http://emberjs.jsbin.com/medamata/6/edit

Related

Problems with rebinding model to a list the second time in ember.js

I am new to Ember and I am trying to make a simple demo app where a list gets rerendered with differrent data when a button is pressed.
Here is a running example of my attempt, by pressing SHOW LIST button a tweet list is shown, and the binding works fine for the first time: http://jsfiddle.net/0xnpav6L/21/
Below are the two places in the code where I've tried to rebind the model to the list:
1)in ApplicationController - I tried to bind the bindNewModel action to the MODIFY button, but it doesn't seem to be working.
2)in ListController - tried to bind bindNewModel action to all the list items(when any list item is pressed), but also that does not seem to work.
App.ApplicationController = Ember.ObjectController.extend({
actions: {
bindNewModel: function() {
console.log(App.ListController);
this.set('model', renderTweets());
}
}
});
App.ListController = Em.ArrayController.extend({
init: function() {
this.set('model', renderTweets());
},
actions: {
bindNewModel: function() {
this.set('model', renderTweets());
}
}
});
Any help would be appreaciated.
Lux is absolutely right with his comments; you are using quite an old version; and I suggest using ember twiddle for demonstrating your ember trials.
Anyway; regarding your code the model at your Application.Controller is not related with what is rendered at #/list. Hence, I only made some modifications to ListController in order to update content when an item is clicked. I set model.data instead of model itself and in handlebars i used {{#each model in this.model.data}} so that it iterates over model's data attribute. Please check the following jsfiddle to see at least it updates properly.
Yet again, it should be much better for you if you read official Ember Guide and get started with Ember's current version 2.12.0.

Hiding elements until load has been completed (ng-cloak isn't what I needed)

I'm writing an AngularJS application, but I'm quite new to it, so in the code below, please point out any issues that you have.
I do have my AngularJS application defines like that:
var OfficeUIModule = angular.module('OfficeUI', ['ngSanitize']);
Then, I do have a couple of services that loads data from various JSon files.
But i won't post the code here, because I do believe that irrelevant.
Then I do have my controller which basically looks like this:
OfficeUIModule.controller('OfficeUIController', function($scope) { });
Now, I want the controller to execute some logic on startup and show a DIV element on it.
Here's the case what I want to do:
Show a Loading DIV element during initial setup.
Show a Displaying DIV element when the initialization has been done.
Let's say that in my controller I do have method to initialize the application:
OfficeUIModule.controller('OfficeUIController', function($scope) {
function Init() {
// I'll load all the data from the services here.
}
});
In order to call this method on startup, I just define it in my controller like so:
OfficeUIModule.controller('OfficeUIController', function($scope) {
Init();
function Init() {
// I'll load all the data from the services here.
}
});
And the HTML which I would like to use is the following:
<body>
<div id="loading">LOADING</div>
<div id="displaying">DISPLAYING</div>
</body>
When the page is initially loaded, I would like to show the element 'Loading'.
When the page has been loaded, I would like to show the element 'Displaying'.
In order to make this testable, I've changed my controller method Init to include a timeout of 5 seconds, just like below:
OfficeUIModule.controller('OfficeUIController', function($scope) {
Init();
function Init() {
setTimeout(function() {
alert('Page has been loaded. When you click OK the displaying DIV should be showed.');
}, 5000);
}
});
So, in this particular case, I would like to make sure that the page is being loaded, displaying the LOADING div and after 5 seconds, display the DISPLAYING div.
I would also like not to see any flickering, and therefore ng-cloak can be used I've read, but I can't manage to configure it correctly.
Here's what I've tried already:
LOADING
DISPLAYING
However, that setup doesn't work quite well.
I've included a Plunker so that you can test the solution you provide.
It happens because you are using setTimeout with anonymous function and angularjs isn't aware of model change
http://plnkr.co/edit/FJ2lnrmtG7P3HXZuxRkH?p=preview
if you use angularjs $timeout it works
$timeout(function() {
$scope.initialized = true;
}, 5000);
you could also use $scope.$digest() or $scope.$apply to make it work
You can use the angular version of window load event.
angular.element($window).bind('load', function(e) {
// code to execute
});

Ember.js load jquery on template render (no refresh)

I have created an ember.js template (about.hbs). I want to run some jQuery on the page but the jQuery only works if I reload the page.
I don't really get where I am meant to put the jQuery code to make it run when the template is rendered. At them moment I have put it in the controller.
App.AboutController = Ember.ObjectController.extend({
$(document).ready(function() {
//my jquery code
});
});
Could someone help me out?
You are going to want to lifecycle callbacks (see Ember docs). When a template is rendered Ember will trigger the didInsertElement callback. You can simply add your own code to this function, and if you want to use any jQuery inside of that callback you must keep the scope in mind: this.$()
Your code will look like this:
didInsertElement: function(){
this.$() //jquery code
}

Combination of $(document).ready and $scope.$on('$viewContentLoaded', function() {...})

I'm using JQuery UI components in a view of AngularJS/JQuery application.
I need something like this (does not work) in my JavaScript code:
$(document).ready(function () {
var elem = $('div[ng-view]')[0];
var $scope = angular.element(elem).scope();
$scope.$on('$viewContentLoaded', function() {
// multiple JQuery statements
// to support JQuery-UI componenets
});
});
This code is included as <script> into index.html that has <div class="container" ng-view> element.
My thinking was that we need a two-step process:
First JQuery reacts on document-ready HTML event and attaches a listener to Angular's $viewContenLoaded using $scope retrieved using [ng-view] element.
Then each time a view is loaded my JQuery code will be executed and JQuery UI components get activated and wired.
Apparently my logic is flawed somewhere. Please point me in the right direction.
ADDITIONAL INFO (posted 03/31/14):
The rest of my code (controllers, service, routing) is written in TypeScript.
That element needs to be compiled in order to bind angulars scope to that element. You could try something like:
var scope = angular.injector(['ng']).get('$rootScope').$new();
var compile = angular.injector(['ng']).get('$compile');
compile(elem)(scope);
scope.$on('$viewContentLoaded', function(){
// Your code
});
Though I would suggest putting your code in a directive. The code I shown above is nothing more than a hack and dangerous since now you have global access to your services.

Backbone :: Using jQuery Plugins on Views

I'm having trouble figuring out a clean way to do this. Let's take for an example a code snippet from the example todo app that comes with backbone:
addOne: function(todo) {
var view = new TodoView({model: todo});
$("#todo-list").append(view.render().el);
},
So the ToDo view is being rendered and then it's being appended to #todo-list. But let's suppose we want to add a jQuery plugin to ToDo view. Where should we place the $(".todo").plugin() snippet? If we place it inside the ToDo view render function the HTML element is not set on the page, so the plugin won't 'latch' to any DOM element. If we place this inside the addOne function it will look ugly.
So, what's the best way?
The answer largely depends on the plugin you're talking about.
For example, most of the jQueryUI controls and the KendoUI controls allow you to call the plugin method from the render of the view, directly, before the HTML is attached to the DOM. You simply call it on the view's el.
For example, if I wanted to use KendoUI's menu on a view that generated:
Backbone.View.extend({
tagName: "ul",
render: function(){
var html = "<li>foo</li><li>bar</li>";
this.$el.html(html);
this.$el.kendoMenu();
}
});
There are some plugins that require the HTML to be a part of the DOM already, for whatever reason. In this case, I typically provide an onShow function in my views, and have the code that is displaying the view check for this and call it if it exists.
For example, there's a "Layout" plugin that I've used a few times. This plugin requires the HTML to be part of the DOM before it can work:
MyView = Backbone.View.extend({
render: function(){
var html = "generate some html here...";
this.$el.html(html);
},
onShow: function(){
this.$el.layout();
}
});
// .... some other place where the view is used
var view = new MyView();
view.render();
$("#someElement").html(view.el);
if (view.onShow) {
view.onShow();
}
FWIW: I've written the code for onShow and other common methods and events dozens of times, and have consolidated it all into a Backbone add-on called Backbone.Marionette, so that I don't have to write it anymore.
http://github.com/derickbailey/backbone.marionette
There's a lot more than just this available in this add-on, of course.
You can use the backbone $ method like so this.$('todo') to use context scoped jquery querying which will allow you to search in the current view DOM fragment which wasn't added to the document DOM tree yet.
From my experience adding jquery plugin binding in either render method or some kind of helper function if there was more custom bindings which would be then called from render method after the template was created.

Categories