Here are my routes:
ExtractCreator.Router.map(function () {
this.route('filter', { path: '/' }, function () {
this.route('geog_levels');
});
});
Here's my view which creates the jquery ui popup:
ExtractCreator.FilterGeogLevelsView = Ember.View.extend({
didInsertElement : function(){
var controller = this.controller;
$('#filter-dialog').dialog({
modal:true,
stack: false,
title: "Geogography Levels Filter",
close: function(e,ui) {
controller.transitionToRoute('filter');
},
}).dialog("moveToTop");
}
});
And the template:
{{#each geog_level_group in model}}
<h3>{{geog_level_group.label}}</h3>
{{#each geog_level_filter in geog_level_group.geog_level_filters}}
<div {{bind-attr class="geog_level_filter.disabled?:disabled"}}>
<label>{{geog_level_filter.label}} - {{geog_level_filter.id}}</label>
{{input type="text" value=geog_level_filter.label }}
</div>
{{/each}}
{{/each}}
I'm binding the inputs to my model in the template, but whenever I type anything in the input field it doesn't update anywhere else on the page, nor does it show as updated in my (chrome) ember inspector's view of the model.
If I change the value manually from the ember inspector, then it updates inside the popup correctly.
If I take it out of the popup (or just remove the popup code), then everything binds correctly and the label will update when I change the input value.
How do I get correct binding behavior to work from inside the dialog?
Well i faced once the same kind of strange behaviors and the problem is mayBe due to the didInsertElement with child views. (yes you some how have child views as you use an each and an ember {{input}} which is a view aswell).
One way which may solve your problem is tu run your modal after ember has finished to render everything in the queue. You may achieve this by modifying your code as follow :
didInsertElement : function(){
var controller = this.controller;
Ember.run.scheduleOnce('afterRender', this ,function(){
$('#filter-dialog').dialog({
modal:true,
stack: false,
title: "Geogography Levels Filter",
close: function(e,ui) {
controller.transitionToRoute('filter');
},}).dialog("moveToTop");
});
}
It turns out that the reason the binding wasn't occurring is that the jQuery-ui dialog function was appending the "#filter-dialog" element to the the body tag, but on creation of my Ember app I used the "rootElement" option to limit the scope of Ember to another div with id of "extract-creator".
My application creation code:
ExtractCreator = Ember.Application.create({
rootElement: '#extract-creator'
});
Using the appendTo option when creating the dialog, I can keep it within the scope of the Ember application:
ExtractCreator.FilterGeogLevelsView = Ember.View.extend({
didInsertElement : function(){
var controller = this.controller;
$('#filter-dialog').dialog({
modal:true,
stack: false,
title: "Geogography Levels Filter",
appendTo: "#extract-creator",
close: function(e,ui) {
controller.transitionToRoute('filter');
},
}).dialog("moveToTop");
}
});
An alternative solution would have been to remove the "rootElement" line from the Ember create option hash, making it default to the body tag.
Special thanks to Buck Doyle for posting a working JSBin in the comments.
Related
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.
I am using backbone js to implement a drag and drop report designer. Now my application can drag and drop report components (title, sub title, table, etc.). I referred this to implement my application. Once the design has been done I can get the related script (on a button click) as below.
saveReportHandler: function(){
console.log($("#target").html());
}
This prints relevant html script for the report design. I want to create a new html page with this script and need to redirect to that newly created page. Since I am a newbie to backbone js, I would be much appreciated any help from you.
My full javascript code looks like below.
var SaveReportView= Backbone.View.extend({
tagName: "textarea",
el: $('#build'), // el attaches to existing element
events: {
'click #saveReport': 'saveReportHandler'
},
initialize: function(){
this.render();
},
//render() now introduces a button to save the report
render: function(){
$(this.el).append("<button id='saveReport' class='btn btn-info'>Save</button>");
},
saveReportHandler: function(){
console.log("#####################");
console.log($("#target").html());
},
});
var reportView= new SaveReportView();
Thank you
In my emberjs app. I have bunch of jquery plugins that I need to bind to various elements.
I am using this piece of code to initiate jquery plugins for elements.
App.ApplicationView = Ember.View.extend({
didInsertElement: function(){
window.appPluginsInit(); // all jquery plugin init
// chart client init
var chartClientSettings = {
serverUrl: config.ajaxUrl
};
this.$('.chart-client').chartClient(chartClientSettings);
}
});
This only works for element that are initially loaded to the page. But for example if an element is under {{#if}} it doesn't seem to be attached with plugins.
Works
<button class="chart-client">Show Chart</button>
Doesn't work
Considering the someVar is false on initial load.
{{#if someVar}}
<button class="chart-client">Show Chart</button>
{{/if}}
You could make your .chart-client element a component and init the plugin on the components didInsertElement.
Component template:
<script type="text/x-handlebars" id="components/chart-client">
Show Chart
</script>
Component:
App.ChartClientComponent = Ember.Component.extend({
classNames: ["chart-client"],
tagName: "button",
chartClientSettings = {
serverUrl: config.ajaxUrl
},
didInsertElement: function () {
this.$().chartClient(this.get("chartClientSettings"));
}
});
Application view:
{{#if someVar}}
{{chart-client}}
{{/if}}
JSBin example: http://emberjs.jsbin.com/wemujo/1/edit?html,css,js,output
The if is parsed after jQuery, delay the jQuery action:
setTimeout((function () {
this.$('.chart-client').chartClient(chartClientSettings);
}).bind(this), 1);
This should do the job.
The solution provided by #Pete TNT is the best but I see 2 other options:
1) instead of putting things in if block, you can probably just use css to show/hide the button. That way the ".chart-client" is always in the DOM tree and hence you can apply the plugin to the element.
<button {{bind-attr class=":chart-client someVar:show:hide"}}>Show Chart</button>
2) Add an observer(also as suggested by #Pete TNT) : http://emberjs.jsbin.com/jekuvixufo/1/
(I would not have posted this but I was already writing a jsbin so I thought why waste my effort.)
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
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.