How do I get clicked elements model in View - Ember - javascript

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.

Related

Backbone - Get user's selected data from DOM or Collection

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.

Backbone, Getting the id/name of the of changed element

I am using Backbone.js with stickit for binding. I have something like below. How do I know which element the user has clicked? (Radio buttons)
initialize: function() {
this.listenTo(this.model, 'change', this.blockDiv);
}
blockDiv : function() {
console.log('The changed element is '+); //How do i know which element the user has changed?
}
bindings : {
'[name=element1]' : element1,
'[name=element2]' : element2
}
You are listening changes from your model, not DOM events directly. You can check what attributes of model have changed with changedAttributes.

ListView doesn't fire selectionchanged

My HTML:
<div id="listViewBoxOffice"
data-win-control="WinJS.UI.ListView"
data-win-options="{ itemTemplate: select('#movieThumbnailTpl'), selectionMode: 'single' }">
</div>
My Javascript:
WinJS.UI.Pages.define("/pages/home/home.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
api.getBoxOffice().done(this.boxOffice, this.errBoxOffice);
listViewBoxOffice.winControl.addEventListener('selectionchanging', this.selectionchanging);
listViewBoxOffice.winControl.addEventListener('selectionchanged', this.selectionchanged);
},
boxOffice: function (movies) {
var list = new WinJS.Binding.List(movies);
listViewBoxOffice.winControl.itemDataSource = list.dataSource;
},
errBoxOffice: function (err) {
debugger;
},
selectionchanged: function (evt) {
console.log('changed');
},
selectionchanging: function (evt) {
console.log('changing');
}
});
My problem:
The event selectionchanged is never fired. The event selectionchanging is fired but with bad value in newSelection.
While the documentation isn't as clear about this as I think it should be, you'll need to set the tapBehavior property to "toggleSelect" so that an item is fully selected. By default, the behavior is invokeOnly and with that it doesn't fully select the item. It clicks, but isn't selected.
There's a decent example located in the MSDN documentation.
If you store off a copy of the listViewBoxOffice instance, then from the events, you can get the current list via a promise:
listViewBoxOffice.selection.getItems().done(function(items) {
// do something with the items...
});
To check wheather the selectionchanged event is working or not Right click on the listview item.I think when we just only click on the listview item it needs iteminvoke event and for selection we need to right click on the item.
Following is the code snipet which is firing the selectionchanged event
<div id="UserListView" data-win-control="WinJS.UI.ListView" style="border-top: 5px solid #000; min-width:500px;"
data-win-options="{
selectionMode:'multi',
itemTemplate:select('#itemsList'),
layout:{
type:WinJS.UI.GridLayout}}"
>
</div>
and in the js
UserListView.addEventListener("selectionchanged", selection);
function selection(evt) {
var test = "testing";
}
set the breakpoint and you can check in the evt the type="selectionchanged"
please try using Item invoked. Here's the Msdn link
Item invoked Winjs Listview
And try changing the selection accordingly.
Also if this does not work or you want selection changed only then Please post in the Template that you have designed. Will need to go through the entire code :)

MooTools: How do I make an object capture a custom event occured in its nested object?

Here's the simplified code:
<html>
<head>
<script type="text/javascript">
var ParentDiv = new Class ({
initialize : function(htmlElement) {
console.log('debug: parent object created');
$$('.childDiv').each(function(childDiv){
childDiv = new ChildDiv(childDiv);
})
htmlElement.addEvents({
'click': function (){
console.log('debug: clicked parent');
},
'testEvent' : function(){
console.log('debug: complex logic altering inner HTML of the element');
}
})
}
});
function initParent () {
$$('.parentDiv').each(function(parentDiv){parentDiv = new ParentDiv(parentDiv);})
}
var ChildDiv = new Class ({
initialize : function(htmlElement) {
console.log('debug: child object created');
htmlElement.addEvent('click', function (){
console.log('debug: clicked child');
this.addEvent('testEvent', function(){console.log('debug: grabbed an event in child element, fired by child element')})
this.fireEvent('testEvent');
})
}
});
document.addEvent('domready', function(){
initParent();
});
</script>
</head>
<body>
<div class="parentDiv">
<div>
<div>
<div>
<div class="childDiv">Clicky Thingy</div>
</div>
</div>
</div>
</div>
</body>
</html>
The outcome is the following: neither of the events are grabbed by parent object's event listeners, while capturing the events is something I'm trying to achieve. A possible occurance of such structure: we have a bunch of control elements on the page, they all fire their own events, while the document or any other kind of container manipulates the content within based on the captured event's type.
So, is there a way to make 'debug: complex logic altering inner HTML of the element' appear in the console box with the use of custom events?
There is a lot wrong with this. To make you life easier, dont use so many nested anonymous functions, they work, but make it hard to untangle sometimes. I cleaned it up and made you a fiddle so you can see how this may work.
http://jsfiddle.net/WQCDd/
You need to learn about event binding to do what you want: https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Also, you were not implementing the "events" on the class so you cant do this.fireevent
A good start to almost any mootools class will look like this:
var ClassName = new Class({
Implements: [Options, Events],
options: {
},
initialize: function(options){
this.setOptions(options);
}
});

How to update knockoutjs view model on user confirm?

I have a edit in place section to which I want to add a confirmation of changes before the knockoutjs model is updated.
Here's the jsFiddle example of what I have now.
Here's what I would like it to do.
User clicks on editable section
textbox appears with save/cancel buttons next to it.
if user makes a change and clicks save, view model is updated
if user makes a change, but decides to keep the original content, they click cancel, view model remains unchanged, texbox is hidden, and editable element remains unchanged.
The behavior of the cancel click is what I'm not sure how to implement. Can anyone suggest how this could be done?
I prefer to use custom binding handler for this.
Example http://jsfiddle.net/7v6Dx/10/
Html
<div>
<span class="editField">
<span data-bind="text: Address1">Click here to edit</span>
<input type="text" data-bind="clickEditor: Address1">
</span>
</div>​
JavaScript
ko.bindingHandlers.clickEditor = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
var $element = $(element).hide();
var $text = $element.prev();
var $buttons = $("<span class='editConfirm'> \
<button class='saveEdit' type='button'>Save</button> \
<button class='cancelEdit' type='button'>Cancel</button> \
</span>").hide().insertAfter($element);
var $editElements = $buttons.add($element);
ko.utils.domNodeDisposal.addDisposeCallback(element, function () {
$buttons.remove();
});
var _toggle = function(edit) {
$text[edit? 'hide' : 'show']();
$editElements[edit? 'show' : 'hide']();
}
$text.click(function(e) {
_toggle(true);
});
$editElements.find('.saveEdit').click(function() {
_toggle(false);
valueAccessor()($element.val());
});
$editElements.find('.cancelEdit').click(function() {
_toggle(false);
$(element).val(ko.utils.unwrapObservable(valueAccessor()));
});
}
, update: function (element, valueAccessor) {
$(element).val(ko.utils.unwrapObservable(valueAccessor()));
}
};
$(document).ready(function() {
var helpText = "Click here to edit";
function appViewModel() {
this.Address1 = ko.observable(helpText);
}
ko.applyBindings(appViewModel());
});​
I was thinking you could probably use a writable computed property to handle this. But it might be easier to just have to separate properties. One property is the real property and the other shadows it. When you bring up the editable section, it's actually bound to the shadow value. When the ok button is clicked, you copy the shadow value to the real value. If cancel is clicked, you do the opposite (copy the real value to the shadow value).

Categories

Resources