backbone.js todomvc add more attributes to model - javascript

I want to try out Backbone.js and started with the famous TodoMVC-App. I want to add some more attributes via input fields (orgiginally there is only one input field with "todo"), but I cant figure out how.
Before I was trying Angular.js and that was a little bit easier - now I am stucked at the point how I should add more attributes per input fields.
Can anyone give me a hint whats the best/easiest way to achieve this?
Some relevant code snippets:
Index.html:
<tr class="userInputs" >
<td><input id="toggle-all" type="checkbox"></td>
<td><input type="text" id="new-todo" placeholder="What needs to be done?" autofocus style="width: 150px"/></td>
<td><input type="text" id="newQuantity"/></td>
<td colspan="2"><a ><img src="img/plus.png" id="addItem"></a></td>
</tr>
model/todo.js
app.Todo = Backbone.Model.extend({
// Default attributes for the todo
// and ensure that each todo created has `title` and `completed` keys.
defaults: {
title: '',
quantity: 0,
completed: false
}
});
views/app.js:
initialize: function() {
this.allCheckbox = this.$('#toggle-all')[0];
this.$input = this.$('#new-todo');
this.$footer = this.$('#footer');
this.$main = this.$('#main');
this.listenTo(app.Todos, 'add', this.addOne);
this.listenTo(app.Todos, 'reset', this.addAll);
this.listenTo(app.Todos, 'change:completed', this.filterOne);
this.listenTo(app.Todos, 'filter', this.filterAll);
this.listenTo(app.Todos, 'all', this.render);
app.Todos.fetch();
}
addOne: function( todo ) {
var view = new app.TodoView({ model: todo });
$('#todo-list').append( view.render().el );
}
newAttributes: function() {
return {
title: this.$input.val().trim(),
quantity: this.$input.val().trim(),
order: app.Todos.nextOrder(),
completed: false
};
}
createOnEnter: function(e) {
app.Todos.create( this.newAttributes() );
this.$input.val('');
}
Hope this is enough information, otherwise please tell me!

Follow the way it's done for the title.
Add a new input.
Change the appView#newAttributes method to pass the new input's value to the model.
Change the appView#createOnEnter method to reset the field.
Change the #item-template to include the new attribute in your Todo template.
Everything else will be automatic (including setting the new attribute to the model (passed as argument) and passing the new attribute to the template (because we use the Model#toJSON method)).
Edit:
this.$input is a reference to this.$('#new-todo') (see the initialize method) so its val is the title. You need to create a new var:
In initialize:
this.$quantity = this.$('#newQuantity');
In newAttributes:
quantity: this.$quantity.val();
// you're not making any check here
// add one if necessary (you can use underscore), eg
// _.isNumber(quantity = this.$('#newQuantity')) ? quantity : 0
// number being declared before, else it'd be global
In createOnEnter:
this.$quantity.val('');

Related

Why does setting an optionsValue break Knockout updating?

I've been going through the Knockout tutorials, and I was playing around with one tutorial when something puzzled me. Here is my HTML:
<h2>Your seat reservations</h2>
<table>
<thead><tr>
<th>Passenger name</th><th>Meal</th><th>Surcharge</th>
</tr></thead>
<tbody data-bind="foreach: seats">
<tr>
<td><input data-bind="value: name" /></td>
<td><select data-bind="options: $root.availableMeals, optionsValue: 'mealVal', optionsText: 'mealName', value: meal"></select></td>
<td data-bind="text: formattedPrice"></td>
</tr>
</tbody>
</table>
<button data-bind="click: addSeat">Reserve another seat</button>
... and here is my JavaScript:
// Class to represent a row in the seat reservations grid
function SeatReservation(name, initialMeal) {
var self = this;
self.name = name;
self.meal = ko.observable(initialMeal);
self.formattedPrice = ko.computed(function() {
var price = self.meal().price;
return price ? "$" + price.toFixed(2) : "None";
});
}
// Overall viewmodel for this screen, along with initial state
function ReservationsViewModel() {
var self = this;
// Non-editable catalog data - would come from the server
self.availableMeals = [
{ mealVal: "STD", mealName: "Standard (sandwich)", price: 0 },
{ mealVal: "PRM", mealName: "Premium (lobster)", price: 34.95 },
{ mealVal: "ULT", mealName: "Ultimate (whole zebra)", price: 290 }
];
// Editable data
self.seats = ko.observableArray([
new SeatReservation("Steve", self.availableMeals[0]),
new SeatReservation("Bert", self.availableMeals[0])
]);
// Operations
self.addSeat = function() {
self.seats.push(new SeatReservation("", self.availableMeals[0]));
}
}
ko.applyBindings(new ReservationsViewModel());
When I run this example and select a different "Meal" from the dropdown menu for a passenger, the "Surcharge" value is not updated. The reason for this seems to be that I added optionsValue: 'mealVal' into the data-bind attribute for the select, and when I remove that, the "Surcharge" does indeed update when a new dropdown option is selected. But why does adding optionsValue break the updating? All that does is set the select list's option value attributes, which is quite useful for form submission - I don't see why it should prevent Knockout from auto-updating.
UPDATE: Upon further investigation, I've discovered that the formattedPrice fn is still getting called, but self.meal() is now resolving to the value string such as PRM instead of the whole meal object. But why is this? The documentation says that optionsValue sets the value attribute in the HTML, but doesn't say anything about changing the view model behaviour.
I think what's going on is that when you specify options: $root.availableMeals, but don't specify an optionsValue, Knockout magically determines which selection in the list you've made when the selection is changed and gives you access to the object from availableMeals instead of just the string value that was put into the value attribute. This does not appear to be well-documented.
I think you understand what's happening and why it breaks your code, but are still looking for an explanation on when you actually need to use optionsValue, and when not.
When to use the optionsValue binding
Let's say your meals can be sold out and you want to check with the server for updates in availableMeals:
const availableMeals = ko.observableArray([]);
const loadMeals = () => getMeals().then(availableMeals);
const selectedMeal = ko.observable(null);
loadMeals();
ko.applyBindings({ loadMeals, availableMeals, selectedMeal });
function getMeals() {
return {
then: function(cb) {
setTimeout(cb.bind(null, [{ mealVal: "STD", mealName: "Standard (sandwich)", price: 0 }, { mealVal: "PRM", mealName: "Premium (lobster)", price: 34.95 }, { mealVal: "ULT", mealName: "Ultimate (whole zebra)", price: 290 }]), 500);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="options: availableMeals,
value: selectedMeal,
optionsText: 'mealName'"></select>
<button data-bind="click: loadMeals">refresh meals</button>
<div data-bind="with: selectedMeal">
You've selected <em data-bind="text: mealName"></em>
</div>
<div data-bind="ifnot: selectedMeal">No selection</div>
<p>Make a selection, click on refresh and notice the selection is lost when new data arrives.</p>
What happens when you replace the objects in availableMeals:
Knockout re-renders the select box's options
Knockout checks the new values for selectedMeal() === mealObject
Knockout does not find the object in selectedMeal and defaults to the first option
Knockout writes the new object's reference to selectedMeal
Problem: you loose your UI selection because the object it points to is no longer in the available options.
optionsValue to the rescue!
The optionsValue allows us to solve this issue. Instead of storing a reference to an object that might be replaced at any time, we store a primitive value, the string inside mealVal, that allows us to check for equality in between different API calls! Knockout now does something like:
selection = newObjects.find(o => o["mealVal"] === selectedMeal());
Let's see this in action:
const availableMeals = ko.observableArray([]);
const loadMeals = () => getMeals().then(availableMeals);
const selectedMeal = ko.observable(null);
loadMeals();
ko.applyBindings({ loadMeals, availableMeals, selectedMeal });
function getMeals() {
return {
then: function(cb) {
setTimeout(cb.bind(null, [{ mealVal: "STD", mealName: "Standard (sandwich)", price: 0 }, { mealVal: "PRM", mealName: "Premium (lobster)", price: 34.95 }, { mealVal: "ULT", mealName: "Ultimate (whole zebra)", price: 290 }]), 500);
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<select data-bind="options: availableMeals,
value: selectedMeal,
optionsText: 'mealName',
optionsValue: 'mealVal'"></select>
<button data-bind="click: loadMeals">refresh meals</button>
<div data-bind="if: selectedMeal">
You've selected <em data-bind="text: selectedMeal"></em>
</div>
<div data-bind="ifnot: selectedMeal">No selection</div>
<p>Make a selection, click on refresh and notice the selection is lost when new data arrives.</p>
The downsides of optionsValue
Notice how I had to rewrite the with binding? Suddenly, we only have one of meal's properties available in our viewmodel, which is quite limiting. Here's where you'll have to do some additional work if you want your app to be able to update its data. Your two options:
Store the string (hash) of your selection and the actual object independently, or
Have a repository of view models, when new server data arrives, map to the existing instances to ensure you keep selection states.
If it helps, I could add code snippets to explain those two approaches a bit better
OK, after looking through the Knockout code, I've figured out what's happening - and as of the time of writing this is not documented.
The value binding, when it reads the value of a select element, doesn't just look at the DOM value for the element; it calls var elementValue = ko.selectExtensions.readValue(element);
Now, what selectExtensions does, unsurprisingly, is implement special behaviour for select (and their child object) elements. This is where the magic happens, because as the comment in the code says:
// Normally, SELECT elements and their OPTIONs can only take value of type 'string' (because the values
// are stored on DOM attributes). ko.selectExtensions provides a way for SELECTs/OPTIONs to have values
// that are arbitrary objects. This is very convenient when implementing things like cascading dropdowns.
So, when the value binding tries to read the select element via selectExtensions.readValue(...), it will come to this code:
case 'select':
return element.selectedIndex >= 0 ? ko.selectExtensions.readValue(element.options[element.selectedIndex]) : undefined;
This basically says "OK, find the selected index and use this function again to read the option element at that index. So then it reads the option element and comes to this:
case 'option':
if (element[hasDomDataExpandoProperty] === true)
return ko.utils.domData.get(element, ko.bindingHandlers.options.optionValueDomDataKey);
return ko.utils.ieVersion <= 7
? (element.getAttributeNode('value') && element.getAttributeNode('value').specified ? element.value : element.text)
: element.value;
Aha! So it stores its own "has DOM data expando property" flag and if that is set it DOESN'T get the simple element.value, but it goes to its own JavaScript memory and gets the value. This is how it can return a complex JS object (like the meal object in my question's example) instead of just the value attribute string. However, if that flag is not set, it does indeed just return the value attribute string.
The writeValue extension, predictably, has the other side of this where it will write the complex data to JS memory if it's not a string, but otherwise it will just store it in the value attribute string for the option:
switch (ko.utils.tagNameLower(element)) {
case 'option':
if (typeof value === "string") {
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, undefined);
if (hasDomDataExpandoProperty in element) { // IE <= 8 throws errors if you delete non-existent properties from a DOM node
delete element[hasDomDataExpandoProperty];
}
element.value = value;
}
else {
// Store arbitrary object using DomData
ko.utils.domData.set(element, ko.bindingHandlers.options.optionValueDomDataKey, value);
element[hasDomDataExpandoProperty] = true;
// Special treatment of numbers is just for backward compatibility. KO 1.2.1 wrote numerical values to element.value.
element.value = typeof value === "number" ? value : "";
}
break;
So yeah, as I suspected, Knockout is storing complex data behind-the-scenes but only when you ask it to store a complex JS object. This explains why, when you don't specify optionsValue: [someStringValue], your computed function received the complex meal object, whereas when you do specify it, you just get the basic string passed in - Knockout is just giving you the string from the option's value attribute.
Personally I think this should be CLEARLY documented because it is a bit unexpected and special behaviour that is potentially confusing, even if it's convenient. I'll be asking them to add it to the documentation.

Group results in autocompleted dropdown [Meteor]

I try to do a dropdown list in my app. First of all I use a Meteor, so that's specific kind of app ofc :)
Second thing is that I use sebdah/meteor-autocompletion package, because I want my results to be sorted in specific way and limited.
The last thing I need is to group my results.
For example: If I have 2 products named "blah" I want to get only 1 "blag" in my dropdown "autocompletion" list.
Some code:
HTML:
<template name="InvoicesEditInsertInsertForm">
<input id="descriptionautocomplete" type="text" name="description" value="" class="form-control" autofocus="autofocus" placeholder="New Item...">
</template>
JS:
Template.InvoicesEditInsertInsertForm.rendered = function() {
AutoCompletion.init("input#descriptionautocomplete");
};
Template.InvoicesEditInsertInsertForm.events({
'keyup input#descriptionautocomplete': function () {
AutoCompletion.autocomplete({
element: 'input#descriptionautocomplete', // DOM identifier for the element
collection: InvoicesItem, // MeteorJS collection object
field: 'description', // Document field name to search for
limit: 5, // Max number of elements to show
sort: { modifiedAt: -1 },
}); // Sort object to filter results with
},
});
I need to use function that could group my "description" here.
I tried to do it in helper and I get it on my screen, but to be honest I don't know how to put that into my dropdown :(
try: function() {
var item= InvoicesItem.find({},{sort:{modifiedAt:-1}}).fetch();
var descriptions={};
_.each(item,function(row){
var description = row.description;
if(descriptions[description]==null)
descriptions[description]={description:description};
});
return _.values(descriptions);
},
I don't think you can do what you want with that package. If you have a look at the current limitations of the package documentation, you can see other potential solutions to your problem.
You can do addtional filtering as follows:
filter: { 'gender': 'female' }});
but I don't think this will allow you to demand only unique options.
The code you wrote above for try won't do anything. Autocomplete doesn't take a field called try.

How to update data in Meteor using Reactivevar

I have a page with a form. In this form user can add multiple rows with key and values. There is a restriction that the customFields is created on the fly, not from any subscribed collection.
...html
<template name="main">
{{#each customFields}}
<div>
<input type="text" value="{{key}}"/>
<input type="text" style="width: 300px;" value="{{value}}"/>
</div>
{{/each}}
</template
.... router.js
Router.route 'products.add',
path: '/products/add/:_id'
data:
customFields:[]
....products.js
#using customFieldSet as Reactive Var from meteor package
Template.product.created = ->
#customFieldSet = new ReactiveVar([])
Template.product.rendered = ->
self = this
Tracker.autorun ->
arr = self.customFieldSet.get()
self.data.customFields = arr
Template.product.events(
'click .productForm__addField': (e)->
t = Template.instance()
m = t.customFieldSet.get()
console.log t
m.push(
key: ''
value: ''
)
t.customFieldSet.set m
....
The last event will be trigger when I click the button. And it add another row with key and value empty to the page.
Please advise me why I actually see the reactive variable customFieldSet updated, but there is nothing changed dynamically in html.
P/s: I guess customFields is not updated via Iron router.
Basically, you're doing the thing right. However, you shouldn't be assigning the new reactive data to your template's data context, but rather access it directly from your helpers:
Template.product.helpers({
customFileds: function () {
return Template.instance().customFiledsSet.get();
},
});
Now you can use {{customFields}} in your template code and it should work reactively. Just remember that {{this.customFileds}} or {{./customFileds}} will not work in this case.

How to render and save dynamic properties of a Backbone Model?

I am totally lost on how to implement a solution for the following problem:
I have a Backbone View that is populated with the properties from a Backbone Model. In this view, the attributes are displayed and for one of the attributes, the user needs to be able to add or modify the existing ones. This would be best suited to be an array of properties within the Backbone Model (I think).
I have added a test case in the js fiddle here
As you can see in the fiddle, the dog's favorite_snacks can be added to by the user, but I have been completely struggling on how to write the code to parse and render this in upon instantiating the view and then save them back to the mysql database successfully.
I would greatly appreciate any help on this, I've been banging my head against my desk all weekend trying to figure it out.
It is always a better idea make sure that views and models behave independently and completely decoupled so that your code can be managed at a later time.
So in this case each Pet can have one or many favorite snacks. So basically you are expecting a collection of snacks here and not a single snack model.
So it is better to create a separate Snacks Collection and then a Snack Model. Then maintain a separate view for SnackListItem and then iterate over the List of SnackCollection and render the view for each item..
So create separate templates for both of them
<div id="foo"></div>
<script type="text/template" id="pet-view-template">
<p> <span><b> Dog Name: </b> </span> <%= name %> </p>
<p> <span><b> Dog Color: </b></span> <%= color %> </p>
<h4> favorite snacks </h4>
<ul class="snacks-list">
</ul>
snack name: <input type="text" class="snack-name" />
cost : <input type="text" class="snack-cost" />
<button class="add-snack">add snack</button >
</script>
<script type="text/template" id="snack-view-template">
<b>snack name:</b> <span> <%=favorite_snacks %> </span> ::
<b>cost: </b><span> <%= favorite_snack_cost %> </span>
<b class="toggle-change"> Change </b>
<span class="modify-fields hide">
<b class="modify">snack name:</b> <input type="text" class="modify-name" data-key="favorite_snacks" />
<b class="modify">snack cost:</b> <input type="text" class="modify-cost" data-key="favorite_snack_cost" />
</span>
</script>
I have created a separate view and models for the Snacks collection. This can still be optimized.
Javascript
// Create a Dog Model
var Dog = Backbone.Model.extend({
defaults: {
name: 'New dog',
color: 'color'
}
});
// Create a collection of dogs
var Dogs = Backbone.Collection.extend({
model: Dog
});
// Create a model for Snacks
var Snack = Backbone.Model.extend({
defaults: {
favorite_snacks: 'bacon',
favorite_snack_cost: '52'
}
});
// Create a collection of Snacks
var Snacks = Backbone.Collection.extend({
model: Snack
});
// Define the model for a Dog
var dog = new Dog({
name: "Spot",
color: "white"
});
// Create a View for the Snack Item
var SnackItemView = Backbone.View.extend({
tagName : 'li',
className: 'snacks',
template: _.template($('#snack-view-template').html()),
initialize: function() {
// Need to bind to save the context of this to the view
_.bind('toggleChange', this);
// Need to listen to the Model change event and render the view again
// as the new data has to be reflected
this.listenTo(this.model, 'change' , this.render);
},
// Assign events for the fields inside Snacks view
events : {
'click .toggle-change' : 'toggleChange',
'change input' : 'modifyData'
},
toggleChange: function() {
var $change = $('.modify-fields', this.$el);
$change.hasClass('hide') ? $change.removeClass('hide') : $change.addClass('hide');
},
// This will captue the data from the inputs and trigger the change event on the model
modifyData: function(e) {
var value = $(e.currentTarget).val(),
key = $(e.currentTarget).data('key');
this.model.set(key,value);
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var PetView = Backbone.View.extend({
el: '#foo',
template: _.template($('#pet-view-template').html()),
initialize: function () {
this.collection = (this.collection && this.collection instanceof Backbone.Collection) || new Snacks(Snack);
},
events: {
'click .add-snack' : 'addSnack'
},
addSnack: function () {
// Render new snack Item
var newSnack = new Snack({
favorite_snacks: $('.snack-name', this.$el).val(),
favorite_snack_cost: $('.snack-cost', this.$el).val()
});
this.renderSnackView(newSnack);
// Clear the inputs
$('input', this.$el).val('');
},
// render each snack view
renderSnackView: function (snack) {
var snackView = new SnackItemView({
model: snack
});
$('.snacks-list', this.$el).append(snackView.el);
snackView.render();
},
render: function () {
var thisView = this;
// Append the PetView
this.$el.html(this.template(this.model.toJSON()));
// Iterate over each snack collection of the pet and render that item
_.each(this.collection.models, function (snack) {
thisView.renderSnackView(snack);
});
return this;
}
});
var petView = new PetView({
model: dog
});
petView.render();
Check the working fiddle
I have used comments to explain some of the code. It is tough to learn backbone initially as i just started working with it recently and i know the trouble I went thru . but once you get used to it it is very simple yet powerful.. Hope this helps :)
But when you try to build an application , you need to destroy the views and events that are not being used in order to reduce memory leaks.

Dynamically adding items into view and posting back to controller (ASP.NET MVC 4)

I have a ASP.NET MVC 4 app with model, that contains and colection (IEnumerable<T> or IList<T>), i.e.:
class MyModel
{
public int Foo { get; set; }
public IList<Item> Bar { get; set; }
}
class Item
{
public string Baz { get; set; }
}
And I render the data in view with classic #for..., #Html.EditorFor... ad so on. Now there's a need to add on client side to add dynamically new items and then post it back to server.
I'm looking for an easy solution to handle the adding (in JavaScript), aka not manually creating all the inputs etc. Probably to get it somehow from editor template view. And to add it the way that when the form is submitted back to server the model binder will be able to properly create the IList<T> collection, aka some smart handling of inputs' names. I read a bunch of articles, but nothing that was easy and worked reliably (without magic strings like collection variable names, AJAX callbacks to server, ...).
So far this looks promising, but I'd like to rather rely on rendering (items known in advance) on server.
I'm not sure what do you mean 'collection variable names' and probably my solution is kind of magic you noticed.
My solution is based on copying existing editor for element and altering input names via Javascript.
First of all, we need to mark up our editor. This is a code of form outputs editor for collection
#for (var i = 0; i < Model.Count; i++)
{
<div class="contact-card">
#Html.LabelFor(c => Model[i].FirstName, "First Name")
#Html.TextBoxFor(c => Model[i].FirstName)
<br />
#Html.LabelFor(c => Model[i].LastName, "Last Name")
#Html.TextBoxFor(c => Model[i].LastName)
<br />
#Html.LabelFor(c => Model[i].Email, "Email")
#Html.TextBoxFor(c => Model[i].Email)
<br />
#Html.LabelFor(c => Model[i].Phone, "Phone")
#Html.TextBoxFor(c => Model[i].Phone)
<hr />
</div>
}
Our editor is placed into div with class contact-card. On rendering, ASP.NET MVC gives names like [0].FirstName, [0].LastName ... [22].FirstName, [22].LastName to inputs used as property editors. On submitting Model Binder converts this to collection of entities based both on indexes and property names.
Next we create javascript function that copies last editor and increases index in brackets by 1. On submitting it adds additional element to collection:
var lastContent = $("#contact-form .contact-card").last().clone();
$("#contact-form .contact-card").last().after(lastContent);
$("#contact-form .contact-card")
.last()
.find("input")
.each(function () {
var currentName = $(this).attr("name");
var regex = /\[([0-9])\]/;
var newName = currentName.replace(regex, '[' + (parseInt(currentName.match(regex)[1]) + 1) + ']');
$(this).val('');
$(this).attr('name', newName);
});
VOILA!! On submitting we will get one more element!
At the end I did similar stuff what STO was suggesting, but with the custom (non-linear) indices for collections suggested by Phil Haack.
This uses manual naming of elements (so I'm not binding directly to the model) and I can use custom instances (for empty element templates). I've also created some helper methods to generate me the code for the instance, so it's easier to generate code for actual instances from the model or empty ones.
I did this with help of Backbone (for file uploader) where i insert template whenever user click #addButton
View:
#using Telerik.Web.Mvc.UI
#{
ViewBag.Title = "FileUpload";
Layout = "~/Areas/Administration/Views/Shared/_AdminLayout.cshtml";
}
<div id="fileViewContainer" class="span12">
<h2>File upload</h2>
#foreach(var fol in (List<string>)ViewBag.Folders){
<span style="cursor: pointer;" class="uploadPath">#fol</span><br/>
}
#using (Html.BeginForm("FileUpload", "CentralAdmin", new { id = "FileUpload" }, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<label for="file1">Path:</label>
<input type="text" style="width:400px;" name="destinacionPath" id="destinacionPath"/><br />
<div id="fileUploadContainer">
<input type="button" class="addButton" id="addUpload" value="Add file"/>
<input type="button" class="removeButton" id="removeUpload" value="Remove file"/>
</div>
<input type="submit" value="Upload" />
}
</div>
<script type="text/template" id="uploadTMP">
<p class="uploadp"><label for="file1">Filename:</label>
<input type="file" name="files" id="files"/></p>
</script>
#{
Html.Telerik().ScriptRegistrar().Scripts(c => c.Add("FileUploadInit.js"));
}
FileUploadInit.js
$(document).ready(function () {
var appInit = new AppInit;
Backbone.history.start();
});
window.FileUploadView = Backbone.View.extend({
initialize: function () {
_.bindAll(this, 'render', 'addUpload', 'removeUpload', 'selectPath');
this.render();
},
render: function () {
var tmp = _.template($("#uploadTMP").html(), {});
$('#fileUploadContainer').prepend(tmp);
return this;
},
events: {
'click .addButton': 'addUpload',
'click .removeButton': 'removeUpload',
'click .uploadPath': 'selectPath'
},
addUpload: function (event) {
this.render();
},
removeUpload: function (event) {
$($('.uploadp')[0]).remove();
},
selectPath: function (event) {
$('#destinacionPath').val($(event.target).html());
}
});
var AppInit = Backbone.Router.extend({
routes: {
"": "defaultRoute"
},
defaultRoute: function (actions) {
var fileView = new FileUploadView({ el: $("#fileViewContainer") });
}
});
In Controller you keep your code
I Hope this will help.

Categories