I'm new to backbone.js and I worked through Jeffery Way's tutorial with Laravel and Backbone. I currently have a list of teams displayed and attached their ids from the database. I set up an event so when I click on a team it sends a get request to laravel and returns all users that have that team id.
The request works great, except I'm stuck trying to generate a usersview. I can't pull out any data from the collection in the App.Views.Users other than an id.
Am I doing this correctly?
View.js
//Global App View
App.Views.App = Backbone.View.extend({
initialize: function() {
var allTeamsView = new App.Views.Teams({ collection: App.teams }).render();
}
});
App.Views.Teams = Backbone.View.extend({
tagName: 'div',
events: {
"click a" : "teamClicked"
},
teamClicked: function(e){
e.preventDefault();
var team_id = e.target.id;
teamusers = new App.Models.Team({id: team_id});
collection = new App.Collections.Teams([teamusers]);
teamusers.fetch();
view = new App.Views.Users({collection: collection, el: '#usersList'});
view.render();
return false;
},
attributes: function() {
return{
class: 'span2 admin teams',
id: 'inner-content-div'
};
},
render: function(){
this.collection.each( this.addOne, this );
return this;
},
addOne: function(team){
var teamView = new App.Views.Team({model: team});
this.$el.append(teamView.render().el);
}
});
// Single Team View
App.Views.Team = Backbone.View.extend({
tagName: 'li',
template: template('allTeamsTemplate'),
attributes: function() {
return{
id: this.model.get('id')
};
},
render: function(){
this.$el.html( this.template( this.model.toJSON() ));
return this;
}
});
App.Views.Users = Backbone.View.extend({
tagName: 'ul',
render: function(){
this.collection.each( this.addOne, this );
console.log(collection);
return this;
},
addOne: function(user){
var userView = new App.Views.User({model: user });
this.$el.append(userView.render().el);
}
});
// Single User View
App.Views.User = Backbone.View.extend({
tagName: 'li',
template: template('allUsersTemplate'),
attributes: function() {
return{
id: this.model.get('id')
};
},
render: function(){
this.$el.html( this.template( this.model.toJSON() ));
return this;
}
});
TeamController.php
public function show($id)
{
return Team::find($id)->user;
}
Index.Blade.php
<div class="teamContainer" id="demo"></div>
<ul class="userContainer" id="usersList"></ul>
<script type="text/template" id="allUsersTemplate">
<p><%= id %></p>
</script>
<script type="text/template" id="allTeamsTemplate">
<a id='<%= teamNum %>' ><%= teamName %></a>
</script>
I got it working. The problem was with my event.
View.js
teamsUserList: function(e){
e.preventDefault();
var team_id = e.target.id;
var collection = new App.Collections.TeamsUsers([], {id: team_id});
collection.fetch().complete(function() {
var view= new App.Views.Users({collection: collection});
$('#usersList').append(view.render().el);
});
},
Related
need help, can't understand how to attach each View of the model to each already existing DIV in DOM ( have and div.container with div.widget array ).
// Model
V.Models.Shortcode = Backbone.Model.extend({});
// Shortcodes Collection Init
V.Collections.Shortcodes = Backbone.Collection.extend({
model: V.Models.Shortcode,
});
When Iframe load, push storage from server to collection:
$('#preview').on('load', function() {
var ShortcodesCollection = new V.Collections.Shortcodes( Vision.ShortcodeStorage );
var Preview = new V.Views.Preview({
collection: ShortcodesCollection,
el: $('.container')
});
Preview.render();
});
Render Preview with collection:
// Collection View in iframe
V.Views.Preview = Backbone.View.extend({
initialize: function() {
this.collection.on('add', this.addOne, this);
},
render: function() {
this.collection.each(this.addOne, this);
return this;
},
addOne: function(ad) {
var shortcodeView = new V.Views.Shortcode({ model: ad });
shortcodeView.render();
}
});
View for each Model:
// Shortcode View
V.Views.Shortcode = Backbone.View.extend({
events: {
'click .widget' : 'SomeActionOnView'
},
render: function(){
//console.log(this.el);
//console.log(this.model.toJSON());
},
SomeActionOnView: function(){
console.log(this);
}
});
Question is, how to attach V.Views.Shortcode to each div with "widget" class to bind events. Thanks!
Can you please try this?
V.Views.Shortcode = Backbone.View.extend({
events: {
'click .widget' : 'SomeActionOnView'
},
render: function(){
//code here to write stuff of this.$el
$("div.widget").append(this.$el);
},
SomeActionOnView: function(){
console.log(this);
}
});
This is my first time using backbone, so I'm pretty confused about everything. I'm trying to make a todo list. Once I click "finished" on the todo, I want it to append to the "Completed" list.
I've been following this tutorial, and I tried to replicate the code(I tried to create a new completedTodo view and stuff like that), and I tried to do when clicking "finished" it would delete the $el, and I would add to the completedTodos. I think the problem here is even if it's added, it's not doing anything.
done: function() {
var completed = new CompletedTodo({
completedTask: this.$('.task').html(),
completedPriority: this.$('.priority').html()
});
completedTodos.add(completed);
this.model.destroy();
},
I put in a debugger there to see if it actually added to the collection, and when i did completedTodos.toJSON();, it does give me back the new thing I just added.
However, it does not append to my collection list.
Here is my whole entire script file, in case I named anything wrong.
var Todo = Backbone.Model.extend({
defaults: {
task: '',
priority: ''
}
});
var CompletedTodo = Backbone.Model.extend({
defaults: {
completedTask: '',
completedPriority: ''
}
});
var Todos = Backbone.Collection.extend({});
var todos = new Todos();
var CompletedTodos = Backbone.Collection.extend({});
var completedTodos = new CompletedTodos();
//Backbone view for one todo
var TodoView = Backbone.View.extend({
model: new Todo(),
tagName: 'tr',
initialize: function() {
this.template = _.template($('.todos-list-template').html());
},
events: {
'click .finished-todo': 'done',
'click .delete-todo' : 'delete'
},
done: function() {
var completed = new CompletedTodo({
completedTask: this.$('.task').html(),
completedPriority: this.$('.priority').html()
});
completedTodos.add(completed);
this.model.destroy();
},
delete: function() {
this.model.destroy();
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
//Backbone view for all todos
var TodosView = Backbone.View.extend({
model: todos,
el: $('.todos-list'),
initialize: function() {
this.model.on('add', this.render, this);
this.model.on('remove', this.render, this);
},
render: function() {
var self = this;
this.$el.html('');
_.each(this.model.toArray(), function(todo) {
self.$el.append((new TodoView({model: todo})).render().$el);
});
return this;
}
});
//View for one Completed Todo
var CompletedTodoView = Backbone.View.extend({
model: new CompletedTodo(),
tagName: 'tr',
initialize: function() {
this.template = _.template($('.completed-todos-template').html());
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
//View for all Completed Todos
var CompletedTodosView = Backbone.View.extend({
model: completedTodos,
el: $('.completed-todos-list'),
initialize: function() {
this.model.on('add', this.render, this);
},
render: function() {
var self = this;
this.$el.html('');
_.each(this.model.toArray(), function(completedTodo) {
self.$el.append((new CompletedTodoView({model: completedTodo})).render().$el);
});
return this;
}
});
var todosView = new TodosView();
$(document).ready(function() {
$('.add-todo').on('click', function() {
var todo = new Todo({
task: $('.task-input').val(),
priority: $('.priority-input').val()
});
$('.task-input').val('');
$('.priority-input').val('');
todos.add(todo);
});
});
After this, I also have to figure out how to use Parse to make it persist to the database. I figured I'd get everything working in backbone first, and then try to do put in the database. I'm also suppose to use node/express, so would that help? I'm pretty much a Ruby on Rails kind of person, so I don't really know any of these javascript framework type of stuff.
Thanks for your help!
Alright,
It was just because I didn't initialize the view.
var completedTodosView = new CompletedTodosView();
This fixed it.
i am working on learn backbone.js, so i decided to make mi own Todo app using backbone.js and a localstorage plugin. I already have the Todo app in wich you can add and remove todos, now I am working on make them sortable in done and not done tasks. But the problem is that i can't find a way to do it. i created a method in the view called sort_done()
sort_done: function(){
var done = this.collection.where({done: true});
console.log(done);
}
But don't know how could i udate the view in order to just show thedone or not done tasks, i appreciate if someone could give me some advice in how i can manage this kind of ´problem. I also leave the model, collection and views js so you can take a look.
Model:
var Task = Backbone.Model.extend({
defaults:{
title: "An empyt task..",
done: false
},
validate: function(attrs){
if(! $.trim(attrs.title)){
return "The task has no title"
}
}
});
var task = new Task;
Collection:
var Tasks = Backbone.Collection.extend({
model: Task,
localStorage: new Backbone.LocalStorage("todos-collection")
});
var tasks = new Tasks();
Views:
var TaskView = Backbone.View.extend({
tagName: "li",
template: _.template( $('#task').html() ),
initialize: function(){
this.model.on('change', this.render, this);
this.model.on('destroy', this.remove, this);
},
render: function(){
var template = this.template( this.model.toJSON() );
this.$el.html( template );
return this;
},
events: {
'click .icon-checkbox': 'toggleState',
'click .task_title': 'editTask',
'keypress .edit': 'updateOnEnter',
'click .close_btn': 'clear'
},
toggleState: function(e){
var $checkbox = $(e.target);
this.model.save('done', !this.model.get('done'));
},
editTask: function(e){
this.task = $(e.target);
this.editBox = this.task.next();
this.editInput = this.editBox.find('.edit');
$(".task_title").removeClass("display__none");
$(".editBox").removeClass("edit_box__editing");
this.task.addClass("display__none")
this.editBox.addClass("edit_box__editing");
this.editInput.attr('placeholder', this.task.text()).focus();
},
updateOnEnter: function(e){
if(e.keyCode === 13){
this.close();
}
},
close: function(){
var value = this.editInput.val();
if(!value){
this.task.removeClass("display__none")
this.editBox.removeClass("edit_box__editing");
}else{
this.model.save({title: value});
this.task.removeClass("display__none")
this.editBox.removeClass("edit_box__editing");
}
},
clear:function(){
this.model.destroy();
}
});
var TasksView = Backbone.View.extend({
el: '#tasks',
initialize: function(){
this.render();
this.collection.on('add', this.addOne, this);
this.collection.on()
},
render: function(){
this.collection.each(this.addOne, this);
return this;
},
addOne: function(task){
var taskView = new TaskView({ model: task });
this.$el.append( taskView.render().el );
}
});
var AddTask = Backbone.View.extend({
el: '#todos',
initialize: function(){
this.collection.fetch();
},
events:{
'click #add': 'addTask',
'click #filter_done': 'sort_done',
'keypress #inputTask': 'updateOnEnter'
},
addTask: function(){
var taskTitle = $('#inputTask'). val();
$('#inputTask').val(""); //clear the input
if($.trim(taskTitle) === ''){//check if the input has some text in it
this.displayMessage("Todo's can not be empty");
}else{
var task = new Task( {title: taskTitle} ); // create the task model
this.collection.create(task); //add the model to the collection
}
},
displayMessage: function(msg){
$('#inputTask').focus().attr("placeholder", msg);
},
updateOnEnter: function(e){
if(e.keyCode === 13){
this.addTask();
}
},
sort_done: function(){
var done = this.collection.where({done: true});
console.log(done);
}
});
var tasksView = new TasksView( {collection: tasks} );
var addTask = new AddTask( {collection: tasks} );
Thank yoou very much!
When you call collection.where your collection is not filtered, it just returning the filtered models (not changing the initial collection), so for your problem you have to do like this :
initialize: function(){
this.render();
this.collection.on('add', this.addOne, this);
this.collection.on('reset', this.render, this); // here I change the event to reset
},
...
sort_done: function(){
var done = this.collection.where({done: true});
this.collection.reset(done);
console.log(done);
}
I still trying to remove (destroy) model from my collection. Data is groupedBy and rendered into accordion style. But when I click to X in my console is notice :
Uncaught Uncaught TypeError: Cannot call method 'destroy' of undefined
(function() {
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
window.vent = _.extend({}, Backbone.Events);
})();
// !models.js
App.Models.Item = Backbone.Model.extend({});
// !collections.js
App.Collections.Items = Backbone.Collection.extend({
model: App.Models.Item,
url: 'api/items.json'
});
// !views.js
App.Views.Items = Backbone.View.extend({
el: '#items',
events: {
'click .cccc':'deleteItem',
},
deleteItem: function() {
this.model.destroy();
},
initialize: function() {
this.listenTo( this.collection, "change", this.render );
this.template = _.template( document.getElementById('productsCategoriesTemlate').innerHTML );
this.render();
this.$el.accordion({ animate: 0 });
},
getGroups : function(){
return _.groupBy(this.collection.toJSON(), 'category');
},
render: function() {
this.el.innerHTML = this.template({ data : this.getGroups() });
},
addOne: function(item) {
// ????????????
}
});
App.Views.Item = Backbone.View.extend({
deleteItem: function() {
this.model.destroy();
},
// ???????????
});
// !router.js
App.Router = Backbone.Router.extend({
routes: {
'':'index',
},
index: function() {
console.log('index page !');
},
});
new App.Router;
Backbone.history.start();
App.items = new App.Collections.Items;
App.items.fetch().then(function() {
new App.Views.Items({ collection: App.items });
});
template :
<script id="productsCategoriesTemlate" type="text/template">
<% _.each( data, function( category, i ){ %>
<h3 class="category-name"><%= i %></h3>
<div><% _.each( category, function( item ){ %>
<li class="product"><%= item.title %><p style="float:right;" class="cccc">X</p></li>
<% }) %>
</div>
<% }) %>
</script>
Where do you instantiate Apps.Views.Items? Is this your 'collection view'? If this view is representing your collection, you have to somehow pass or reference the model on 'deleteItem'.
App.Views.Items does not represent a single model, so this.model would be incorrect.
UPDATE
You should have a separate view for each item, such as App.Views.Item, and loop through and create this view for each model in App.Views.Items' collection.
2nd UPDATE
Yeah, you are getting it. Here's some sample code I threw together (I haven't tested it, so you might have to adjust it, but it gives a good idea. The template rendering syntax might be incorrect as I don't usually do it manually).
App.Views.Items = Backbone.View.extend({
render: function() {
this.collection.each(function(model) {
var view = new App.Views.Item({ model: model });
this.$el.append(view.render().el);
});
},
});
App.Views.Item = Backbone.View.extend({
template: _.template($('#itemViewTemplate')),
render: function() {
this.$el.html(this.template(this.model.toJSON()));
},
});
App.items = new App.Collections.Items;
App.items.fetch().then(function() {
var items = new App.Views.Items({ collection: App.items });
$('body').append(items.render().$el);
});
By the way, once you get the hang of Backbone and how it works, you should try out Marionette.js. It makes all of this kind of thing much simpler.
Hey guys here is my js file and I am taking error message about each function at line:24 and I do not know why I couldnt find whats wrong. I am just trying to see the list of items on the console.log panel but it does not even give me list on the html page.
(function() {
window.App = {
Models: {},
Collections: {},
Views: {}
};
window.template = function(id){
return _.template( $('#' + id).html() );
};
App.Models.Task = Backbone.Model.extend({});
App.Collections.Task = Backbone.Collection.extend({
model: App.Models.Task
});
App.Views.Tasks = Backbone.View.extend({
tagName: 'ul',
render: function(){
this.collection.each( this.addOne, this);
return this;
},
addOne: function(task){
//creating new child view
var taskView = new App.Views.Task({ model: task });
//append to the root element
this.$el.append(taskView.render().el);
}
});
App.Views.Task = Backbone.View.extend({
tagName: 'li',
template: template('taskTemplate'),
events: {
'click .edit': 'editTask'
},
editTask: function(){
alert('you are editing the tas.');
},
render: function(){
var template = this.template( this.model.toJSON() );
this.$el.html(template);
return this;
}
});
var tasksCollection = new App.Views.Task([
{
title: 'Go to the store',
priority: 4
},
{
title: 'Go to the mall',
priority: 3
},
{
title: 'get to work',
priority: 5
}
]);
var tasksView = new App.Views.Tasks({ collection: tasksCollection });
$('.tasks').html(tasksView.render().el);
})();
You're creating a view instance as though it was a class:
App.Views.Tasks = Backbone.View.extend({ /* ... */ });
var tasksCollection = new App.Views.Task([
{
title: 'Go to the store',
priority: 4
},
//...
and then you create another instance of that view and hand it tasksCollection as though it really was a collection:
var tasksView = new App.Views.Tasks({ collection: tasksCollection });
But views and collections are different things and only collection's have an each method (unless you add an each to your view of course).
You want to create tasksCollection as an App.Collections.Task:
var tasksCollection = new App.Collections.Task([
{
title: 'Go to the store',
priority: 4
},
//...
Hi this is happening cus your each method not able to find the collection. As well the singular Task to Tasks
At this line:
Change this
var tasksCollection = new App.Views.Task([
TO, this:
var tasksCollection = new App.Collections.Tasks([