What I'm doing:
I'm creating a sample app that shows how to incorporate Kendo UI controls with Backbone.js using Rails 3 as a JSON server.
So far, I have Backbone Views that are managing templates in an erb file and a Backbone Router that is managing the Views themselves - depending on the links that are clicked.
When this is finished, I want to make it all available as a tutorial to help folks who want to get into Backbone - and KendoUI (which is pretty damn cool as well).
The Problem:
The Kendo grid is not rendering through the Users View render method - even though it's container template is.
Right now, I am having to render the grid from the Users method of the Router - after the router has rendered the User view.
It seems odd that the template renders, but the grid does not - or am I missing something?
Maybe it will be simpler to understand once you see the code:
index.html.erb
<h1>Kendo Grid Test</h1>
<div id="nav"></div>
<div id="container">
<!-- The templates below will be placed here dynamically -->
</div>
<!-- TEMPLATES -->
<script type="text/template" id="users-grid-template">
<p>Users Grid Template</p>
<div id="users-grid"></div>
</script>
<script type="text/template" id="posts-grid-template">
<div id="posts-grid"></div>
</script>
<script type="text/template" id="nav-template">
<div>
<ul id="nav_container">
<li><a href="#users">Users</a></li>
<li><a href="#posts">Posts</a></li>
</ul>
</div>
</script>
Backbone Users View
window.UsersView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, "render");
this.usersGrid = _.template($("#users-grid-template").html());
this.render().el;
},
render: function() {
$(this.el).html(this.usersGrid).fadeIn();
return this;
}
});
Backbone Router
window.AppRouter = Backbone.Router.extend({
routes: {
'users': 'users',
'posts': 'posts'
},
initialize: function() {
this.usersView = new UsersView;
},
posts: function() {
var container = $("#container");
container.empty();
},
users: function() {
var container = $("#container");
container.empty();
container.append(this.usersView.render().el);
var UsersData = new kendo.data.DataSource({
transport: {
read: {
url: "/users",
dataType: "json"
}
}
});
var grid = $("#users-grid").kendoGrid({
dataSource: UsersData,
columns: [
{
field: "first_name",
title: "First Name"
},
{
field: "last_name",
title: "Last Name",
}]
});
container.append(grid);
}
});
window.App = new AppRouter();
Backbone.history.start();
As you can see, the Kendo UI grid is dynamically generated and placed into the <div id="users-grid"></div>
of the "users-grid-template". But, I have to do a separate 'append' method in order to get the grid into the template. This seems unnecessary.
It seems like I should be able to place all of this...
... inside of the UsersView Render method - without having to use the append method. But I can't get that to work.
Any suggestions on how to structure this? Or whether or not my current code is structured correctly?
Advice much appreciated!
EDIT - Simplified Solution (thanks to Derick)
I realized that I was over-complicating this. I was trying to use Backbone to do what Kendo was already doing - managing its grid and datasource.
Since Backbone is so modular, and all I really needed for the moment was it's Router, I removed all the views - except for the Navigation view - and just used the Router and let Kendo do its thing.
I think the solution is much simpler and easier to manage code. (at least for me)
$(document).ready(function(){
window.Navigation = Backbone.View.extend({
el: $("#nav"),
initialize: function() {
_.bindAll(this, "render");
this.nav = $("#nav-template").html();
this.render().el;
},
render: function() {
$(this.el).html(this.nav);
return this;
}
});
window.nav = new Navigation;
window.AppRouter = Backbone.Router.extend({
routes: {
'users': 'users',
'posts': 'posts'
},
initialize: function() {
var container = $("#container");
//container.html("#users-grid");
},
posts: function() {
var container = $("#container");
container.empty();
},
users: function() {
var container = $("#container");
usersTemplate = _.template($("#users-grid-template").html());
container.empty();
container.html(usersTemplate);
var UsersData = new kendo.data.DataSource({
transport: {
read: {
url: "/users",
dataType: "json"
}
}
});
$("#users-grid").kendoGrid({
dataSource: UsersData,
columns: [
{
field: "first_name",
title: "First Name"
},
{
field: "last_name",
title: "Last Name",
}]
});
}
});
window.App = new AppRouter();
Backbone.history.start();
// Closing jquery tag
});
Hopefully someone will find this useful.
Next step - apply CRUD to this.
the problem is caused by lack of scoping the selector when trying to call .kendoGrid
. Stuffing your contents in to the el.html(...)
doesn't attach your view's el
to the DOM, so a call to $("#users-grid")
doesn't have anything to find, yet.
You can still call kendoGrid
on the view's el, but you have to scope your "#user-grid" selector to the view to do it:
Backbone.View.extend({
render: function(){
this.$el.html(this.usersGrid);
this.$("#user-grid").kendoGrid({
// kendo grid options here
});
}
});
calling this.$
as a function on a view is a shortcut method on the view, to use the el
as the context for your jquery selector. It's the same as calling this.$el.find("#users-grid")
FWIW: I'm using Kendo a lot these days, and loving it with Backbone. I haven't yet run in to a Kendo control that needs any real special handling outside of a view's render method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With