I'm at a loss as to what's going on here. I think it's because I'm loading the form later on in the view, but I'm honestly not sure. Here's my view.
define([
'jquery',
'underscore',
'backbone',
'serializeForm',
'backboneForms',
'text!templates/services/ServicesTemplate.html',
'models/ServiceModel',
'forms/NewServiceForm',
'text!templates/forms/ServiceFormTemplate.html',
'collections/RegionsCollection',
'collections/UsersCollection'
], function($, _, Backbone, serializeForm, backboneForms, ServicesTemplate, ServiceModel,
NewServiceForm, ServiceFormTemplate, RegionsCollection, UsersCollection){
// The form
var form;
// What's gonna be clicked
var clicked;
// Get the user's credentials
if($.cookie('UserInfo'))
var userCreds = JSON.parse($.cookie('UserInfo'));
var ServicesView = Backbone.View.extend({
el: '.body',
render: function() {
// Load everything
var servicesTemplate = _.template(ServicesTemplate);
this.$el.html(servicesTemplate);
},
events: {
'click .btn': 'loadForm',
'submit': 'addService'
},
loadForm: function(ev) {
// Save what was clicked
clicked = $(ev.target).html();
// Save the scope
var that = this;
// Create the regions collection
var regionsCollection = new RegionsCollection();
var serviceModel = new ServiceModel();
var serviceFormTemplate = _.template(ServiceFormTemplate);
// Create the form
form = new NewServiceForm({
template: serviceFormTemplate,
model: serviceModel
}).render();
$("#form").html(form.el);
$('.body').on('submit', 'form', function() {
alert( "submit firing" );
});
},
addService: function(ev) {
var errors = form.commit();
if(!errors) {
var newService = $(ev.currentTarget).serializeForm();
newService.cluster = clicked;
console.log(newService);
} else {
$.each(errors, function(key, value) {
$("[name='" + key + "']").closest(".control-group").addClass("error");
$("[name='" + key + "']").closest(".control-group").find(".text-error").html("<small class='control-group error'>" + value.message + "</small>");
});
}
return false;
}
});
return ServicesView;
});
I've tried to bind the event to just the form that gets generated and, as you can see above, I've tried just catching any submit event. Any help on this is greatly appreciated.
EDIT: Here's what my index page looks like
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>Backbone Auth</title>
<?php include('includes/head_includes.php'); ?>
</head>
<body>
<div class="header"></div>
<div class="container body">
</div>
<?php include('includes/js_files.php'); ?>
</body>
</html>
And here's roughly what my form looks like. The .control-groups all get populated with fields using the backbone-forms extension.
<form id="addservice" accept-charset="UTF-8">
<div id="error" class="alert alert-error" style="display:none;"></div>
<fieldset>
<div class="control-group">
<div class="controls">
<label>Region</label>
<div class="text-error"></div>
<div data-editors="region"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label>Stage</label>
<div class="text-error"></div>
<div data-editors="stage"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label>Description</label>
<div class="text-error"></div>
<div data-editors="description"></div>
</div>
</div>
<div class="control-group">
<div class="controls">
<label>Primary Contact</label>
<div class="text-error"></div>
<div data-editors="contact"></div>
</div>
</div>
<input id="AddService" class="btn btn-primary" type="submit" name="submit" value="Add Service" />
</fieldset>
</form>
EDIT2: Here is my NewServiceForm
define([
'jquery',
'underscore',
'backbone',
'backboneForms'
], function($, _, Backbone, backboneForms){
var NewServiceForm = Backbone.Form.extend({
schema: {
region: {
type: 'Select',
title: 'Disaster Region',
options: [],
validators: [
'required'
]
},
stage: {
type: 'Select',
title: 'Stage',
options: [
{val: "", label: "Select One"},
{val: "Assessment", label: "Assessment"},
{val: "Planned", label: "Planned"},
{val: "Commenced", label: "Commenced"}
],
validators: [
'required'
]
},
description: {
type: 'TextArea',
title: 'Description',
editorAttrs: {
maxlength: 140
},
validators: [
'required'
]
},
contact: {
type: 'Select',
title: 'Primary Contact',
options: [],
validators: [
'required'
]
}
}
});
return NewServiceForm;
});
WOOP!! Finally figured this out! I went ahead and moved the rendering of the form into the render function of the view. So now render looks like this:
render: function() {
var serviceModel = new ServiceModel();
var serviceFormTemplate = _.template(ServiceFormTemplate);
// Create the form
form = new NewServiceForm({
template: serviceFormTemplate,
model: serviceModel
}).render();
// Load everything
var servicesTemplate = _.template(ServicesTemplate);
this.$el.html(servicesTemplate);
}
Everything else stays the same. And now it works!
Related
I've reading and trying some codes but nothing has been working like I want i to... this is the code I have right now.
index.html:
<div class="form-group">
<label for="accommodation">3.2. ACCOMMODATION (*)</label> <br />
<div>
{{view Ember.RadioButton name="accommodation" valueBinding='accommodation' selectionBinding="isSelected" value="Not Required"}}
Not Required
</div> <br />
<div>
{{view Ember.RadioButton name="accommodation" valueBinding='accommodation' selectionBinding="isSelected" value="Required"}}
Required
</div>
</div>
View radiobutton.js:
Ember.RadioButton = Ember.View.extend({
tagName: "input",
type: "radio",
attributeBindings: ["name", "type", "value", "checked:checked:"],
click: function () {
this.set("selection", this.$().val())
},
checked: function () {
return this.get("value") == this.get("selection");
if (this.get("selection") == "Required") {
$('#panelAccommodation').style.display = "block";
}
if (this.get("selection") == "Not Required") {
$('#panelAccommodation').style.display = "none";
}
}.property()
What I want from these RadioButtonLists is to be able to retrieve the value of the selected item so I can send it as a POST to a api and to use the selected value to hide/show a div dependidng on the selected value. Any ideas on how to do this?
EDIT:
I'm trying andrusieczko's code and so far I have this:
radio.js :
App.RadioView = Ember.View.extend({
tagName: 'input',
type: 'radio',
attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name'],
htmlChecked: function () {
return this.get('value') === this.get('checked');
}.property('value', 'checked'),
change: function () {
this.set('checked', this.get('value'));
},
_updateElementValue: function () {
Ember.run.next(this, function () {
this.$().prop('checked', this.get('htmlChecked'));
});
}.observes('htmlChecked')
});
Ember.Handlebars.helper('radio-button', App.RadioView);
controller:
App.EventsNewController = Ember.ObjectController.extend({
acRequired: 'Required',
acNotRequired: 'Not Required',
accommodation: null,
Index.html :
<div class="form-group">
<label for="accommodation">3.2. ACCOMMODATION (*)</label> <br />
<div>
{{radio-button value=acRequired checked=accommodation}}
Not Required
</div>
<div>
{{radio-button value=acNotRequired checked=accommodation}}
Required
</div>
</div>
still not sending the selected value on the POST request.
EDIT 2:
I've written some code that in all others aspects is behaving like I want it to but it's still not binding the selected value to the property I want it to.
View radio.js:
Ember.Radio = Ember.View.extend({
tagName: "input",
type: "radio",
attributeBindings: ["name", "type", "value", "checked:checked:"],
click: function () {
this.set("selection", this.$().val())
if(this.get("selection") === "acRequired") {
$('#panelAccommodation').css("display", "block");
this.set("selection", "Required");
selectionBinding: "App.event.accommodation"
}
if (this.get("selection") === "acNotRequired") {
$('#panelAccommodation').css("display", "none");
this.set("selection", "Not Required");
selectionBinding: "App.event.accommodation"
}
if (this.get("selection") === "flRequired") {
$('#panelFlight').css("display", "block");
this.set("selection", "Required");
selectionBinding: "App.event.flight"
}
if (this.get("selection") === "flNotRequired") {
$('#panelFlight').css("display", "none");
this.set("selection", "Not Required");
selectionBinding: "App.event.flight"
}
},
checked: function () {
return this.get("value") == this.get("selection");
}.property()
});
Index.html :
<!-- Accommodation - RadioButtonList -->
<div class="form-group">
<label for="accommodation">3.2. ACCOMMODATION (*)</label> <br />
<div>
{{view Ember.Radio name="accommodation" selectionBinding='accommodation' value="acNotRequired"}}
Not Required
</div>
<div>
{{view Ember.Radio name="accommodation" selectionBinding='accommodation' value="acRequired"}}
Required
</div>
</div>
controller new.js :
App.EventsNewController = Ember.ObjectController.extend({
accommodation: "Not Required",
flight: "Not Required",
actions: {
save: function () {
var self = this;
this.get('model').set('status', 'Created');
this.get('model').save().then(function () {
self.transitionToRoute('events.table');
});
}
}
});
PS: I'm using Ember version 1.6.1
If you're not using either Ember App Kit or ember-cli, then all you have to do is:
App.RadioView = Ember.View.extend({
tagName: 'input',
type: 'radio',
attributeBindings: ['type', 'htmlChecked:checked', 'value', 'name'],
htmlChecked: function() {
return this.get('value') === this.get('checked');
}.property('value', 'checked'),
change: function() {
this.set('checked', this.get('value'));
},
_updateElementValue: function() {
Ember.run.next(this, function() {
this.$().prop('checked', this.get('htmlChecked'));
});
}.observes('htmlChecked')
});
Ember.Handlebars.helper('radio-button', App.RadioView);
Then, in your Controller:
App.IndexController = Ember.Controller.extend({
country1: 'USA',
country2: 'Singapore',
country3: 'Poland',
country: null,
});
and in your template:
{{radio-button value=country1 checked=country}}
{{radio-button value=country2 checked=country}}
{{radio-button value=country3 checked=country}}
and you can listen to the properties you passed to the helper and based on that trigger other actions.
And it can be easily used along with {{each}} :)
Does it help?
The working example (Ember 1.6.1, ember-data 1.0.0-beta.9):
https://github.com/andrusieczko/radiobutton-example.git
Disclaimer: I'm not the author of the code, I took it from somewhere some time ago.
If you can handle not using HTML <input> elements, try using this component that I wrote.
Note that I'm using Ember 1.10 and Ember-CLI.
my-template.js (controller)
import Ember from 'ember';
export default Ember.Controller.extend({
options: [Ember.Object.create({
name: "Required",
value: "1",
}), Ember.Object.create({
name: "Not Required",
value: "0",
})],
actions: {
optionChanged: function(option) {
// option.value will either be 1 or 0 in this case.
}
}
});
my-template.hbs
{{#mutex-button-set key="value" default=options.firstObject stateChanged="optionChanged" buttons=options as |button|}}
<div>{{button.name}}</div>
{{/mutex-button-set}}
mutex-button-set.hbs
{{#each button in buttons}}
<div {{bind-attr class=":mutex-button button.selected:selected"}} {{action "setSelected" button}}>
{{yield button}}
</div>
{{/each}}
mutex-button-set.js
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['mutex-button-set'],
actions: {
setSelected: function(obj) {
var key = this.get("key");
this.get("buttons").forEach(function(button) {
Ember.set(button, "selected", obj && (button.get(key) === obj.get(key)));
});
if (obj) {
this.sendAction('stateChanged', obj);
}
}
},
didInsertElement: function() {
this.send("setSelected", this.get("default"));
}
});
HTML Generated
<div id="ember554" class="ember-view mutex-button-set">
<div data-ember-action="559" class="mutex-button selected">
<div>Required</div>
</div>
<div data-ember-action="563" class="mutex-button ">
<div>Not Required</div>
</div>
</div>
I am creating a page where users can order reports as PDF. I have tried to create it using Angular. When the user changes a report type, this is correctly updated in the debug information present on the page. However, the request for a report is sent as JSON and I would prefer if this JSON object was updated automatically as well. As it is now, I have to click on the "Create JSON" button for it to be updated.
This example can be seen over at JSFiddle as well: http://jsfiddle.net/HenricF/wgvd7wLx/2/
IMPORTANT
The JSON object will not only include the report type, but also a lot of other options not shown here. These options include accounts, languages and dates and the JSON object should preferably be updated whenever anyone of these are changed. I am sorry for not mentioning this initially.
HTML
<body ng-app="OrderPageApp">
<div id="all" ng-controller="ReportController">
<div id="top">
<div class="pagesection" id="ChooseReportType">
<h3>Select report type</h3>
<select id="dropdownlist" ng-change="setAccountTypes(chosenReport)" ng-options="report.name for report in reports" ng-model="chosenReport"></select>
</div>
<div class="pagesection" id="ChooseLanguage">
<h3>Select language</h3>
<select id="dropdownlist" ng-options="language.name for language in languages" ng-model="chosenLanguage"></select>
</div>
<div class="pagesection" id="IncludeHeadlines">
<h4>Include headlines</h4>
<input name="includeHeadlines" type="checkbox" ng-model="includeHeadlines">
</div>
<div class="bottom" id="bottom">
<h4>Selected report</h4>
<div id="reportName">Name: {{name}}</div>
<div id="reportCode">Code: {{code}}</div>
<div id="Language">Language: {{chosenLanguage.code}}</div>
<div id="includeHeadlines">Include headlines: {{includeHeadlines}}</div>
<h4>JSON data</h4>
<input type="button" value="Create JSON" ng-click="showJson()">
<div id="pdfData"><pre>{{pdfData}}</pre>
</div>
</div>
</div>
JS
var reportTypes = [{
name: 'Report type 1',
code: 1
}, {
name: 'Report type 2',
code: 2
}, {
name: 'Report type 3',
code: 3
}];
var languages = [{
name: 'Swedish',
code: 1053
}, {
name: 'English',
code: 1033
}];
var app = angular.module('OrderPageApp', []);
app.controller('ReportController', function ($scope) {
$scope.reports = reportTypes;
$scope.languages = languages;
$scope.setAccountTypes = function (chosenReport) {
$scope.name = chosenReport.name;
$scope.code = chosenReport.code;
};
$scope.showJson = function () {
$scope.pdfData = angular.toJson(new CreatePdfData($scope.name, $scope.chosenLanguage, $scope.includeHeadlines));
};
function CreatePdfData(reportType, chosenLanguage, includeHeadlines) {
this.reportType = reportType;
this.chosenLanguage = chosenLanguage.code;
this.includeHeadlines = includeHeadlines;
};
})
I ended up solving it like this (thanks to the input from deitch and Dipali Vasani):
The pdfData was updated manually as soon as any input was changed - I couldn't figure out a way to have it update automatically.
This is how I did it in HTML:
<input name="includeHeadlines" type="checkbox" ng-model="includeHeadlines" ng-change="showJson()">
And this is how I did it in JS:
$scope.setAccountTypes = function (chosenReport) {
...
$scope.showJson();
};
try this changes :
var reportTypes = [{
name: 'Report type 1',
code: 1
}, {
name: 'Report type 2',
code: 2
}, {
name: 'Report type 3',
code: 3
}];
var languages = [{
name: 'Swedish',
code: 1053
}, {
name: 'English',
code: 1033
}];
var app = angular.module('OrderPageApp', []);
app.controller('ReportController', function($scope) {
$scope.reports = reportTypes;
$scope.languages = languages;
$scope.setAccountTypes = function(chosenReport) {
$scope.name = chosenReport.name;
$scope.code = chosenReport.code;
};
$scope.showJson = function() {
var name = $scope.name;
var chosenLanguage = $scope.chosenLanguage;
var includeHeadlines = $scope.includeHeadlines;
if (name == undefined) {
name = null;
}
if (chosenLanguage == undefined) {
chosenLanguage = null;
}
if (includeHeadlines == undefined) {
includeHeadlines = false;
}
$scope.pdfData = angular.toJson(new CreatePdfData(name, chosenLanguage, includeHeadlines));
};
function CreatePdfData(reportType, chosenLanguage, includeHeadlines) {
this.reportType = reportType;
this.chosenLanguage = chosenLanguage != null ? chosenLanguage.code : null;
this.includeHeadlines = includeHeadlines;
};
})
<body ng-app="OrderPageApp">
<div id="all" ng-controller="ReportController">
<div id="top">
<div class="pagesection" id="ChooseReportType">
<h3>Select report type</h3>
<select id="dropdownlist" ng-change="setAccountTypes(chosenReport);showJson()" ng-options="report.name for report in reports" ng-model="chosenReport"></select>
</div>
<div class="pagesection" id="ChooseLanguage">
<h3>Select language</h3>
<select id="dropdownlist" ng-options="language.name for language in languages" ng-model="chosenLanguage" ng-change="showJson()"></select>
</div>
<div class="pagesection" id="IncludeHeadlines">
<h4>Include headlines</h4>
<input name="includeHeadlines" type="checkbox" ng-model="includeHeadlines" ng-change="showJson()">
</div>
<div class="bottom" id="bottom">
<h4>Selected report</h4>
<div id="reportName">Name: {{name}}</div>
<div id="reportCode">Code: {{code}}</div>
<div id="Language">Language: {{chosenLanguage.code}}</div>
<div id="includeHeadlines">Include headlines: {{includeHeadlines}}</div>
<h4>JSON data</h4>
<input type="button" value="Create JSON" ng-click="showJson()">
<div id="pdfData"><pre>{{pdfData}}</pre>
</div>
</div>
</div>
</body>
JSFiddle
This will solve your problem
jsfiddle
I'm trying to create a message client using this tutorial at this point, the view is supposed to be updated when a new message is typed into the field and the add button is clicked.
For some reason the "addMessage" Event is failing to add a new model to the collection.
var messagesjson = [
{
id: 3,
message: "This is the message",
sender: "gabriel",
receiver: "gabriel",
has_been_read: false,
has_been_reported: false,
created_at: "2014-10-23T19:55:20+0200",
is_friend: false
},
{
id: 5,
message: "I'm loving this ",
sender: "gabriel",
receiver: "gabriel",
has_been_read: true,
has_been_reported: false,
created_at: "2014-10-23T20:02:34+0200",
is_friend: false
}];
var MessageModel = Backbone.Model.extend({
defaults:
{
id: 3,
message: "This is the message",
sender: "gabriel",
receiver: "gabriel",
has_been_read: false,
has_been_reported: false,
created_at: "2014-10-23T19:55:20+0200",
is_friend: false
}
});
var MessageView = Backbone.View.extend({
tagName: "div",
className: "listview",
template: $('#messageTemplate').html(),
render: function()
{
var tmpl = _.template(this.template);
console.log(this.model);
this.$el.html(tmpl(this.model.toJSON()));
return this;
}
});
var MessageCollection = Backbone.Collection.extend({
model: MessageModel
});
var MessageCollectionView = Backbone.View.extend({
el: $('#messages'),
initialize: function()
{
this.collection = new MessageCollection(messagesjson);
this.render();
this.collection.on("add", this.renderMessage, this);
},
render: function()
{
var that = this;
_.each(this.collection.models, function(item){
that.renderMessage(item);
},this);
},
events:{
"click #add":"addMessage"
},
renderMessage: function(item)
{
var messageview = new MessageView({
model: item
});
this.$el.append(messageview.render().el);
},
addMessage: function(e)
{
e.preventDefault();
var formData = {};
$("#addMessage").children("input").each(function (i, el) {
formData[el.id] = $(el).val();
});
messagesjson.push(formData);
this.collection.add(new MessageModel(formData));
console.log(messagesjson);
}
});
var messagecollectionview = new MessageCollectionView();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.1.2/backbone-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.7.0/underscore-min.js"></script>
<div id="messages">
<form id="addMessage" action="#">
<div>
<label for="messageText">Message: </label>
<input id="messageText" type="text" />
<button id="add">Add</button>
</div>
</form>
</div>
<script type="text/template" id="messageTemplate">
<a href="#" class="list autoWidth <% if(has_been_read) { %> selected <% } %>">
<div class="list-content">
<img src="//www.polyvore.com/cgi/img-thing?.out=jpg&size=l&tid=20774792" class="icon">
<div class="data">
<span class="item-title-secondary fg-gray"><b><%= sender %></b></span>
</div>
<span class="tertiary-text">
<%= message %>
</span>
</div>
</a>
</script>
You are setting the id as 3 for all new models as your defaults hash contains id: 3. The collection thinks it is the same model as it already has a model with that id.
So first you need to change your defaults with id:null:
var MessageModel = Backbone.Model.extend({
defaults:{
id: null,
message: "This is the message",
sender: "gabriel",
receiver: "gabriel",
has_been_read: false,
has_been_reported: false,
created_at: "2014-10-23T19:55:20+0200",
is_friend: false
}
});
Then you need to fix the code getting the formData. First of all you are using jQuery children() method which only looks at immediate childrens. That means you will never get the inputs inside the form as there is an intermediate div. You could use find.
Secondly, you need to make sure that formData has a property named message so it can override the default message: "This is the message". I would add a name attribute message to the input element and use it like formData[el.name] = $(el).val();. (You could later use one of the jquery serializeObject plugins to automatically serialize all input elements this way).
So the addMessage would look like this:
addMessage: function(e){
e.preventDefault();
var formData = {};
$("#addMessage").find("input").each(function (i, el) {
formData[el.name] = $(el).val();
});
messagesjson.push(formData);
this.collection.add(new MessageModel(formData));
}
You can try it in this fiddle
I have next problem with function each. I wanna render all tables from collection, after that add function for create new table. But I don't know why I have in console error:
Uncaught TypeError: Cannot call method 'each' of undefined
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Backbone test</title>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/css/bootstrap.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<header>
<div class="jumbotron">
<div class="container">
<h1>My tables!</h1>
</div>
</div>
</header>
<content>
<div id="add-table">
<div class="container">
<label>Add new table!</label>
<form>
<legend>Name</legend>
<div class="input-group">
<span class="input-group-btn">
<button class="btn btn-default" type="button">Go!</button>
</span>
<input type="text" class="form-control">
</div>
</form>
</div>
</div>
<div id="content"></div>
</content>
<script id="allTableTemlate" type="text/template">
<li><%= name %></li>
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.1/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js"></script>
<script>
// !main.js
(function() {
window.App = {
Models: {},
Collections: {},
Views: {},
Router: {}
};
window.vent = _.extend({}, Backbone.Events);
window.template = function(id) {
return _.template( $('#' + id).html() );
};
})();
// !models.js
App.Models.Table = Backbone.Model.extend({});
// !collections.js
App.Collections.Tables = Backbone.Collection.extend({
model: App.Models.Table,
url: 'tables.json'
});
// !views.js
App.Views.App = Backbone.View.extend({
initialize: function() {
var allTablesView = new App.Views.Tables({ collection: App.tables }).render();
$(document.body).append(allTablesView.el);
}
});
App.Views.Tables = Backbone.View.extend({
tagName: 'ul',
render: function() {
this.collection.each( this.addOne, this );
return this;
},
addOne: function(table) {
var tableView = new App.Views.Tables({ model: table });
this.$el.append(tableView.render().el);
},
});
App.Views.Table = Backbone.View.extend({
tagName: 'li',
template: template('allTableTemlate'),
render: function() {
this.$el.html( this.template( this.model.toJSON() ) );
return this;
},
});
// !router.js
App.Router = Backbone.Router.extend({
routes: {
'':'index',
},
index: function() {
console.log('index page !');
},
});
// !index.html
new App.Router;
Backbone.history.start();
App.tables = new App.Collections.Tables;
App.tables.fetch().then(function() {
new App.Views.App({ collection: App.tables });
});
</script>
</body>
</html>
This is my complete code with json data :
[
{"name": "Table 1","stts": "redstts","id": 1},
{"name": "Table 2","stts": "redstts","id": 2},
{"name": "Table 3","stts": "redstts","id": 3},
{"name": "Table 4","stts": "redstts","id": 4},
{"name": "Table 5","stts": "redstts","id": 5}
]
There is a typo in your addOne function. You should be creating a new "App.Views.Table" instead of "new App.Views.Tables" :
addOne: function(table) {
var tableView = new App.Views.Table({ model: table });
this.$el.append(tableView.render().el);
}
I have some sort of ViewCollection which renders all sub views.
define(
['jquery', 'underscore', 'backbone', 'text!templates/main/layout.html', 'text!templates/main/index.html', 'views/security/login', 'views/security/registration'],
function($, _, Backbone, LayoutTemplate, ContentTemplate, LoginView, RegistrationView) {
var IndexView = Backbone.View.extend({
tagName: "div",
className: "container",
template: LayoutTemplate,
render: function() {
this.$el.html(LayoutTemplate);
this.$('div.content').html(ContentTemplate);
this.$('div.sidebar').append(new LoginView().render().el);
this.$('div.sidebar').append(new RegistrationView().render().el);
return this;
}
});
return IndexView;
});
This works quite good!
Unfortunatly I have noticed that for example the LoginView can't handle events anymore.
define(
['jquery', 'underscore', 'backbone', 'text!templates/security/login.html'],
function($, _, Backbone, LoginTemplate){
var LoginView = Backbone.View.extend({
tagName: "form",
className: "login well",
template: LoginTemplate,
events: {
"submit form.login": "submit"
},
render: function(){
this.$el.html(this.template);
return this;
},
submit: function(e){
e.preventDefault();
var credentials = {
'username': $(e.target[1]).val()
, 'password': $(e.target[2]).val()
};
console.log(JSON.stringify(credentials));
$.ajax({
url: '/session'
, type: 'POST'
, contentType: 'application/json'
, data: JSON.stringify(credentials)
, success: function() {
window.Router.navigate('node', { trigger: true });
}
, error: function(xhr, status, error) {
console.log([xhr, status, error]);
$(e.target[1]).closest('div.control-group').addClass('error');
$(e.target[2]).closest('div.control-group').addClass('error');
}
});
}
});
return LoginView;
});
Instead of sending an ajax call the browser tries to submit the form data url-encoded as GET request that is a sign that the view doesn't listen on any views anymore...
Is there a option how I can rebind the view events to the element?
login.html
<fieldset>
<legend>login</legend>
<div class="control-group">
<label class="control-label" for="_session_username">username:</label>
<div class="controls">
<input type="text" id="_session_username" name="session[username]" placeholder="george78" />
</div>
</div>
<div class="control-group">
<label class="control-label" for="_session_password">password:</label>
<div class="controls">
<input type="password" id="_session_password" name="session[password]" placeholder="••••••" />
</div>
</div>
<button type="submit" class="btn btn-primary">login</button>
</fieldset>
the form tags are defined in the view also the .login class attribute.
I found the solution.
We have a scoping problem. Because I defined the form directly in the view (tagName: "form") the topest object is "form.login". But this we can't address through the selector anymore. We only can select child objects. (See Backbone internals).
Before:
events: {
'keyup form.login input': 'checkInput'
, 'submit form.login': 'submit'
},
After:
events: {
'keyup input': 'checkInput'
, 'submit': 'submit'
},