I have one Backbone Collection (named themeCollection) which items are listed on the webpage (DOM). The user can select one item from that list. I need to save user's selected item into the database together with other information. It comes out two ways from my head to implement this feature.
1) Get the selected list item from the DOM (by jquery)
addCard: function(e) {
e.preventDefault();
var formData = {};
// Get data from the form
$( '#modal-new-card form' ).children( 'input' ).each( function( i, el ) {
if ( $(el).val() != '' ) {
formData[ el.id ] = $(el).val();
}
$(el).val('');
});
// Get selected listed item from the DOM.
formData['theme'] = this.$el.find('div.colorSelected').attr('color');
// Code for saving into the database
// ...
}
2) Get the selected list item from the Backbone Collection
addCard: function(e) {
e.preventDefault();
var formData = {};
$( '#modal-new-card form' ).children( 'input' ).each( function( i, el ) {
if ( $(el).val() != '' ) {
formData[ el.id ] = $(el).val();
}
$(el).val('');
});
formData['theme'] = this.themeCollection.findWhere({selected: true});
}
The first way seems to me a little awkward. It touches DOM so it closely coupled upon the DOM. That's not good. Whenever the CSS class is changed, my app would be stopped working.
The second way would be a little more jobs to be done. I have to change themeModel's selected attribute to be true whenever the user clicks. When changing, I also have to set false to selected attributes of all other models in the collection.
Which way would be the better choice? If you have any other ways, please share me and suggest me.
It appears you need to learn more about Backbone, but I'll try to help...
You should be using a Model for maintaining the form data and add events via View to update model when things change. Upon submit, you can call model.toJSON() to save to the DB.
var NewCard = Backbone.Model.extend({
defaults: {
question: '',
explanation: '',
color: 'Blue'
}
})
Then setup a collection to hold the colors to select
var colors = new Backbone.Collection([
{color: 'Blue'},
{color: 'Gray'}
]);
Here is a working example
The example is far from complete, but should give you a picture.
Looks like that you shouldn't store it like Collection.
If it's only about choosing a color, it's better store it as model attribute ({"theme": "purple"}) and then send this model to server.
Markup:
<input type="radion" name="theme" value="yellow">
<input type="radion" name="theme" value="purple">
Your view:
function changeTheme() {
var cardData = this.$el.serializeArray(); // jQuery just for brevity
this.model.trigger('THEME_CHANGE', cardData);
}
Backbone.Collection.extend({
tagName: 'form',
events: {
'change [name="theme"]': changeTheme
}
});
Model just listen for THEME_CHANGE and process data.
Related
I am currently using the isotope plugin to create a function that allows me to place multiple select dropdowns. When the user has selected the dropdowns and when they click submit, it fires the event and rearranges the items.
The problem i am recieving is that the change event is firing and removing everything, but when i click submit, the right results are returned.
Jquery:
jQuery(document).ready(function($) {
var $container = $('.finalblock'),
filters = {},
selector;
$container.isotope({
itemSelector : '.finalchannel',
layoutMode: 'none'
});
$('select').change(function(){
var $this = $(this);
$('#mainSubmission').click(function() {
var group = $this.attr('data-filter-group');
filters[ group ] = $this.find(':selected').attr('data-filter-value');
var isoFilters = [];
for ( var prop in filters ) {
isoFilters.push( filters[ prop ] )
}
var selector = isoFilters.join('');
$container.isotope({ filter: selector });
return false;
});
});
});
Iv been looking into the bind() function but that doesnt seem to be giving me the right thing (maybe cause i must be doing something wrong.
$('select').bind('initCheckboxes change', function() {
// do some stuff including ajax work
}).trigger('initCheckboxes');
EDIT:
JSFIDDLE: http://jsfiddle.net/Lnzkv3v7/
Just looking at your code, (on the website itself, not the jsfiddle):
The first select element has the id of filters
<select id="filters" data-filter-group="mainfilter">
but did you know that was stored as a variable in your js?
var $container = $('.finalblock'),
filters = {},
selector;
Since most of these elements are being pulled in by Isotope anyways, this could be the issue. The reason why this is a theory is because your second select element doesnt seem to be causing an issue. So change the first select id to something else and see if it works.
I have a view with number of divs in rows. When I click on a div the current clicked element should be selected. Below is the code I have used.
{{#each}}
<div {{action target="view" on="click" allowedKeys="shift"}} {{bind-attr class=':user isActive'}} >
{{test}}
</div>
{{/each}}
My view is backed by a model as:
model: function() {
return [{'test':'1'}, {'test' :'2'}, {'test': '3'}, {'test': '4'}];
}
In my view I handled the click handler.
click: function( e ) {
if( e.shiftKey ){
this.modelFor("index").send('changeBgSelection', {'test' :'2'} ); // Here I could not get the current clicked elements model.
}
// Here I need to get the current clicked elements model. When I click the second element I need to get as "{'test' :'2'}". But I could not get the current elements model. Instead I can get the whole model.
}
In my Route,
Here the clicked element is made active.
actions:{
changeBgSelection: function (params) {
var select = this.get("controller").objectAt(this.modelFor("index").indexOf(params));
select.set('isActive', true)
}
}
So how do I get the current clicked elements model in my View? So that I can pass the model to my Route to make the clicked div active with Shift key is pressed.
Edited: Jsbin Link
There are two ways to respond to a mouse click in Ember:
Call an action
Handle it in a view
It seems you tried to combine the two and it became a mess. I'm sure there's a way to make it work, but I can't find it. Instead, allow me to propose an alternative.
In general, if there's something fancy going on with javascript or event handling (like the SHIFT key in your example), I like to deal with it in a localized view. Here, each 'TestView' is tied to a single model instance, which it manipulates based on user input.
<script type="text/x-handlebars" data-template-name="index">
{{#each}}
{{#view App.TestView content=this}}
{{this.test}}
{{/view}}
{{/each}}
</script>
App = Ember.Application.create();
function wrap(ob) {
return Ember.Object.create(ob);
}
App.IndexRoute = Ember.Route.extend({
model: function() {
return [
wrap({'test':'1', 'isActive':false}),
wrap({'test' :'2', 'isActive':false}),
wrap({'test': '3', 'isActive':false}),
wrap({'test': '4', 'isActive':false})
];
}
});
App.TestView = Ember.View.extend({
classNames: ["user"],
classNameBindings: ["content.isActive:is-active"],
click: function(e) {
if (e.shiftKey) {
this.get("content").toggleProperty("isActive");
}
}
});
This can be cleaned up some more, but you get the gist. Live demo here.
I'm new to kendo I have a list populated from a data source (with template : Each list item has mobile switch in it).I need to get all the id's of selected mobile switches when I clicked on a single button. Can anyone let me know how to do that in kendo ?
Cheers,
Chinthaka
I solved that Using following code (Only Active Items checked items)
var checkedWorkCentersIds = new Array();
$('#workcenters :checkbox:checked').map(function () {
if (this.checked == true) {
checkedWorkCentersIds.push(this.id);
}
});
Without the code it is hard to give an exact answer, but you should be able to just loop over the data items in the array and find the ones that are selected.
For example:
var dataSource = new kendo.data.DataSource( ... );
function getSelected() {
return $.grep(dataSource.view(), function (item) {
return item.selected;
});
}
Assuming the switches/checkboxes are bound to the "selected" property.
In response to your comment, you can get the selected checkbox element IDs with jQuery:
$("#workcenters :checkbox:checked").map(function (index, checkbox) {
return $(checkbox).attr("id");
});
I've just started to use CKEditor and I can't manage to understand the API well enough to accomplish what I am aiming for.
Essentially, I have a few instances of the editor on the page. However, for the editor by the name of htmlInput, I want to collect the names of the form elements that are added to the editor. The closest I've gotten is to have an alert pop up when the appropriate dialogs are opened, but I haven't been able to extract the value of the name field of these boxes.
Here's what I have so far.
CKEDITOR.on('dialogDefinition', function (e) {
var dialogName = e.data.name;
var dialog = e.data.definition.dialog;
if(e.editor.name == 'htmlInput' && (dialogName=='checkbox' || dialogName=='radio' || dialogName=='textfield' || dialogName == 'textarea' || dialogName == 'select'))
{
dialog.on('show', function (ev) {
alert('here');
});
}
});
What you're trying to do is very unsafe. Imagine what if someone pasted such form element or used editor.insertHtml() method. They won't be collected. The better approach is as follows:
var form = {};
CKEDITOR.instances.editor1.dataProcessor.htmlFilter.addRules({
elements: {
$: function( element ) {
if ( element.name in { 'input' : 1, 'textarea': 1, 'button' : 1 } ) {
if ( !form[ element.name ] )
form[ element.name ] = [];
form[ element.name ].push( element );
}
}
}
});
Now when you can basically do the following:
CKEDITOR.instances.editor1.getData();
console.log( form );
Then you'll retrieve all the form elements (or elements of any kind) that belong to the document. Just make sure your form object is empty when serializing forms since i.e. htmlFilter is also executed when switching between souce mode <-> wysiwyg and it will continuously populate your list.
You can also basically use the following to retrieve elements by tag name (simple way IMO):
CKEDITOR.instances.editor1.document.getElementsByTag( 'input' );
Before explaining the problem I am facing,this is the code I am using:
<!DOCTYPE HTML>
<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.1/underscore-min.js"></script>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script type="text/template" id="view_template">
<li>
<label class="lbl" style="width:100px;display:inline-block;"><%= name %></label>
<button class="btn">Click</button>
</li>
</script>
<script type="text/javascript">
AppModel = Backbone.Model.extend({
defaults : {
m_name : "Default name"
},
modify : function(value) {
this.set({
m_name : value
});
}
});
$(document).ready(function() {
$("#add").click(function() {
var appModel = new AppModel();
appModel.modify($("#txt").val());
new CustomView({
model : appModel
});
$("#txt").val("");
});
CustomView = Backbone.View.extend({
el : $(".list"),
events : {
"click .btn" : "showAlert"
},
initialize : function() {
this.render();
},
render : function() {
var variables = {
name : this.model.get("m_name")
};
var t = _.template($("#view_template").html(), variables);
$(this.el).append(t);
},
showAlert : function() {
alert(this.model.get("m_name"));
}
});
});
</script>
</head>
<body>
<input type="text" id="txt"/>
<button id="add">
Add
</button>
<ul class="list" style="list-style: none"></ul>
</body>
</html>
A demo is here - http://jsfiddle.net/jCekv/
You can type any value into textfield and click Add.The text will be added to a list which is a backbone view.You can keep on adding multiple values to the list.After adding some items,click on the Click button in any of the items in the list.I want to get the value in the model for that view.But because of the way I am adding Events,event handlers are getting executed multiple times.For eg:If i add 3 items and click on any of the buttons in the list 3 alerts will come-one corresponding to each of the items that is added.This is not the way I want.I want to have the event being triggered only for the Backbone View which has been clicked so that I get access to the model of the Backbone View I have clicked.
How I can achieve this functionality?.Please let me know if my question is not clear.Thanks in advance.
The problem is that all your CustomViews have their element set to $(".list"). Therefore, all delegate events are added to the same DOM element, the list, and not the individual list items.
See a possible solution here: http://jsfiddle.net/mbuchetics/R8jPA/
I changed the CustomView to use a tagName of li instead of setting the element. The template is not appended to the element but instead its content is set. This way, each CustomView represents one item of the list and the click event refers to exactly that item.
I also removed the render call from initialize, instead the view is rendered when it is appended to the list (in the "add click" callback).
Render() returns this and therefore you can use view.render().el to get the list item's html.
You could further improve your application to use collections and a separate view for the collection. The collection view could then handle events such as "add" on the collection and update itself (and the individual item views) accordingly.
This is because you're creating a new instance of the view class for each item, assigning the same DOM element (which corresponds to the whole list, not an individual item) to each instance, and registering the same event listener. So each time you click any of the buttons, the event listener fires for each view object.
Something like this will work:
http://jsfiddle.net/jCekv/1/
$( document ).ready( function () {
$( "#add" ).click( function () {
var appModel = new AppModel();
appModel.modify( $( "#txt" ).val() );
var item = new Item_View( {
model : appModel
} );
list.add_item( item );
$( "#txt" ).val( "" );
} );
var List_View = Backbone.View.extend( {
el : $( ".list" ),
events : {
"click .btn" : "showAlert"
},
initialize : function () {
this.render();
},
add_item : function ( item ) {
item.render();
item.$el.data( 'view_object', item );
this.$el.append( item.el );
},
showAlert : function ( event ) {
alert(
$( event.target )
.closest( 'li' )
.data( 'view_object' )
.model.get( "m_name" )
);
}
} );
var Item_View = Backbone.View.extend( {
tagName : 'li',
render : function() {
var variables = {
name : this.model.get( "m_name" )
};
var t = _.template( $( "#view_template" ).html(), variables );
this.$el.html( $( t ).html() );
return this;
}
} );
var list = new List_View;
} );
I created separate view classes for the list and for items.
I'm storing a reference to the view object for each item using jQuery.data, so that the view object (and via that, the model object) can be retrieved inside the event listener (showAlert). Alternatively you could maintain an array of the items' view objects in the list view. I already have this setup to perform adding items through an add_item method of the list view, so that would facilitate maintaining such an array of item view objects.