Edit an object in backbone - object

I am new to using backbone in parse.com environment. I simply want to edit the second model object but I dont know how to open the edit box for the second object.
The current working model is the following, I have added "dblclick label.todo-job" : "edit1" and can get it started by double clicking it.
events: {
"click .toggle" : "toggleDone",
"dblclick label.todo-content" : "edit",
"dblclick label.todo-job" : "edit1",
"click .todo-destroy" : "clear",
"keypress .edit" : "updateOnEnter",
"blur .edit" : "close"
},
The following is the function to allow editing my object.
edit1: function() {
$(this.el).addClass("editing");
this.input.focus();
},
However, it only opens this object "label.todo-content" to edit while I want to edit "label.todo-job". How can I change the focus to the new object.
Thats the whole code if you need.
// The DOM element for a todo item...
var TodoView = Parse.View.extend({
//... is a list tag.
tagName: "li",
// Cache the template function for a single item.
template: _.template($('#item-template').html()),
// The DOM events specific to an item.
events: {
"click .toggle" : "toggleDone",
"dblclick label.todo-content" : "edit",
"dblclick label.todo-job" : "edit1",
"dblclick label.todo-phone" : "edit2",
"dblclick label.todo-email" : "edit3",
"dblclick label.todo-website" : "edit4",
"dblclick label.todo-address" : "edit5",
"click .todo-destroy" : "clear",
"keypress .edit" : "updateOnEnter",
"blur .edit" : "close"
},
// The TodoView listens for changes to its model, re-rendering. Since there's
// a one-to-one correspondence between a Todo and a TodoView in this
// app, we set a direct reference on the model for convenience.
initialize: function() {
_.bindAll(this, 'render', 'close', 'remove');
this.model.bind('change', this.render);
this.model.bind('destroy', this.remove);
},
// Re-render the contents of the todo item.
render: function() {
$(this.el).html(this.template(this.model.toJSON()));
this.input = this.$('.edit');
return this;
},
// Toggle the `"done"` state of the model.
toggleDone: function() {
this.model.toggle();
},
// Switch this view into `"editing"` mode, displaying the input field.
edit: function() {
$(this.el).addClass("editing");
this.input.focus();
},
edit1: function() {
$(this.el).addClass("editing");
this.input.focus();
},
edit2: function() {
$(this.el).addClass("editing");
this.input.focus();
},
edit3: function() {
$(this.el).addClass("editing");
this.input.focus();
},
edit4: function() {
$(this.el).addClass("editing");
this.input.focus();
},
edit5: function() {
$(this.el).addClass("editing");
this.input.focus();
},
// Close the `"editing"` mode, saving changes to the todo.
close: function() {
this.model.save({content: this.input.val()});
$(this.el).removeClass("editing");
},
// If you hit `enter`, we're through editing the item.
updateOnEnter: function(e) {
if (e.keyCode == 13) this.close();
},
// Remove the item, destroy the model.
clear: function() {
this.model.destroy();
}
});
Below is the objects added in the HTML.
<script type="text/template" id="item-template">
<li class="<%= done ? 'completed' : '' %>">
<div class="view">
<li><label class="todo-content"><%= _.escape(content) %></label></li>
<li><label class="todo-job"><%= _.escape(job) %></label></li>
<li><label class="todo-phone"><%= _.escape(phone) %></label></li>
<li><label class="todo-email"><%= _.escape(email) %></label></li>
<li><label class="todo-website"><%= _.escape(web) %></label></li>
<li><label class="todo-address"><%= _.escape(address) %></label></li>
<li><label class="todo-postcode"><%= _.escape(postcode) %></label></li>
<button class="todo-destroy"></button>
</div>
<input class="edit" value="<%= _.escape(content) %>">
<input class="edit" value="<%= _.escape(content) %>"> /*I need to edit this instead of the object above this*/
</li>
</script>

An event triggers on the deepest possible element.which means this of Event handler function is not element you select for event listener but element where the actual event occurs.
I don't know about parse.com though,I assume that label.todo-content is inside of label.todo-job. And that makes Event handler's callback this into label.todo-content.
So If you explicitly select element to focus,It should work.
FYI, Backbone View has $(http://backbonejs.org/#View-dollar) and $el (http://backbonejs.org/#View-$el) parameters to use jQuery methods for elements in side of the View.Since global $ is able to edit any elements over each controller's View area, using this.$ is always recommended.
edit1: function() {
this.$el.addClass("editing");
this.$("label.todo-job").focus();
},
EDITED
I got what you asked about.
I do not know how you wrote your HTML code but the code you provided is pointing first input if your input tags have class name,
edit1: function() {
this.$el.addClass("editing");
this.$(".yourClassNameForInput").focus();
},
or if you do know have class/id name,You can also do this.
edit1: function() {
this.$el.addClass("editing");
this.$("input").eq(0).focus();
},
....
edit5: function() {
this.$el.addClass("editing");
this.$("label.todo-job").eq(4).focus();
}

Related

Liferay 7 date picker does not trigger onChange

I added this AUI date picker to my JSP:
<aui:input
type="text"
id="myDate"
name="my-date"
value="2017-12-14"
placeholder="yyyy-mm-dd"
onChange="javascript:alert('date changed');"/>
<aui:script>
AUI().use(
'aui-datepicker',
function(A) {
new A.DatePicker(
{
trigger: '#<portlet:namespace/>myDate',
mask: '%Y-%m-%d',
popover: {
zIndex: 1000
}
}
);
}
);
</aui:script>
Problem: Changing the date using the calendar widget that pops up does not display the alert.
If I ignore the widget and change the date manually (using the keyboard), the alert correctly shows up as soon as the input loses focus.
What am I doing wrong?
How to have onChange be called whenever the date is changed, be via mouse or keyboard?
As the guys in the comments mentioned use the js callback definitions. There are a couple of examples in the documentation.
https://alloyui.com/examples/datepicker
If you really want to have the onChange also there, you can trigger the change event from the js callback code.
<button class="btn btn-primary"><i class="icon-calendar icon-white"></i> Select the date</button>
<script>
YUI().use(
'aui-datepicker',
function(Y) {
new Y.DatePicker(
{
trigger: 'button',
popover: {
zIndex: 1
},
on: {
selectionChange: function(event) {
console.log(event.newSelection)
}
}
}
);
}
);
</script>

YUI3 Datatable loaded with JSON displays only no results to display (Scala/Play 2.1)

I am new to YUI but I veteran of JQuery UI. So this one has me stumped. I cannot get my Datatable to render with the Rest service. I have two version of the code. One that I use the captured JSON object from the service as just a data object and a local datasource. That one works fine. When I attempt to switch to the GET plugin and get it from the service. It just never renders.
My local example:
#main("Play 2.1") {
<script type="text/javascript">
YUI().use("datatable", "datasource-local", "datasource-jsonschema", "datatable-datasource", function (Y) {
var data = [
{"script":{"id":34534,
"scriptText":"234523452345234",
"modifiedDate":1367525647000,
"status":"Reviewed",
"qcDate":1367526006000,
"location":{"id":1},
"orderInfo":{"id":1,
"orderName":"Order Name",
"dealerName":"Dealer Name"}
}},
{"script":{"id":656435,
"scriptText":"36536543636365",
"modifiedDate":1367525646000,
"status":"Reviewed",
"qcDate":1367526017000,
"location":{"id":1},
"orderInfo":{"id":43534534,
"orderName":"Order Name",
"dealerName":"Dealer Name"}
}}
];
var localDataSource = new Y.DataSource.Local({source:data});
localDataSource.plug(Y.Plugin.DataSourceJSONSchema, {
schema:{
resultListLocator:"",
resultFields:[
{
key:"id",
locator:"script.id"
},
{
key:"scriptText",
locator:"script.scriptText"
},
{
key:"modifiedDate",
locator:"script.modifiedDate"
}
]
}
});
var simple = new Y.DataTable({
columns:["id", "scriptText", "modifiedDate"],
summary:"Example Summary",
caption:"Example Caption"
});
simple.plug(Y.Plugin.DataTableDataSource, {
datasource:localDataSource
});
simple.render("#dataGrid");
simple.datasource.load();
});
</script>
<span id="listView">
<div id="dataGrid" style="height: 95%;width: 100%;"></div>
</span>
<div id="dataCheckArea">
<h3>RAW DATA AREA</h3>
<ul>
#records.map {record =>
<li>#record.toString</li>
}
</ul>
</div>
}
My REST Service example:
#main("Welcome to Play 2.1") {
<script type="text/javascript">
YUI().use("datatable", "datasource-get", "datasource-jsonschema", "datatable-datasource", function (Y) {
var dataSource = new Y.DataSource.Get({
source:"http://localhost:9000/reviewRecords?q=query"
});
dataSource.plug(Y.Plugin.DataSourceJSONSchema, {
schema:{
resultListLocator:"",
resultFields:[
{
key:"id",
locator:"script.id"
},
{
key:"scriptText",
locator:"script.scriptText"
},
{
key:"modifiedDate",
locator:"script.modifiedDate"
}
]
}
});
var dataGrid = new Y.DataTable({
columns:["id", "scriptText", "modifiedDate"],
summary:"Example Summary",
caption:"Example Caption"
});
dataGrid.plug(Y.Plugin.DataTableDataSource, { datasource:dataSource });
dataGrid.render("#dataGrid");
dataGrid.datasource.load();
});
</script>
<span id="listView">
<div id="dataGrid" style="height: 95%;width: 100%;"></div>
</span>
** edited because the original submission lost my second code block.
The problem wasn't with my javascript code. The issue was with how I was sending the response. The YUI framework expects that the response will be wrapped in a callback function. When I changed my response to give a JSONP response with the callback it all started working.
YUI.Env.DataSource.callbacks.yui_3_11_0_1_1379097239018_187([
{"script":{"id":34534,
"scriptText":"234523452345234",
"modifiedDate":1367525647000,
"status":"Reviewed",
"qcDate":1367526006000,
"location":{"id":1},
"orderInfo":{"id":1,
"orderName":"Order Name",
"dealerName":"Dealer Name"}
}},
{"script":{"id":656435,
"scriptText":"36536543636365",
"modifiedDate":1367525646000,
"status":"Reviewed",
"qcDate":1367526017000,
"location":{"id":1},
"orderInfo":{"id":43534534,
"orderName":"Order Name",
"dealerName":"Dealer Name"}
}}
])
I did this by using a JSONP call in the method response from Scala/Play 2.1
def reviewRecords(q: String, callback: String) = Action {
val reviewRecords = reviewRecordsService.currentReviewRecords
Ok(new Jsonp(callback, Json.toJson(DataTablesReturnObject(reviewRecords.size, reviewRecords.toArray)))).as("application/json")
}
I am going to edit the title of my original question to include the keywords for Play 2.1 and Scala because this ends up being a little different than a Java response.

How to integrate Stripe "Pay with Card" in backbonejs

I am trying to integrate Stripe "Pay with Card" checkout into backbone Node environment. On the server side, I am using Stripe Node code - that part works good. However, on the client side, I am unable to capture the event.
I would like to capture the submit event from the Stripe popup to call "paymentcharge" method in the view.
Here is my code:
<!-- Stripe Payments Form Template -->
<form id="stripepaymentform" class="paymentformclass">
<script
src="https://checkout.stripe.com/v2/checkout.js" class="stripe-button"
data-key="pk_test_xxxxxxxxxxxxx"
data-amount="0299"
data-name="MyDemo"
data-description="charge for something"
data-image="assets\ico\icon-72.png">
</script>
</form>
Backbone View Class
myprog.PaymentPanelView = Backbone.View.extend({
initialize: function () {
this.render();
},
render: function () {
$(this.el).html(this.template());
return this;
},
events : {
"submit" : "paymentcharge"
},
paymentcharge : function( event) {
this.model.set({stripeToken: stripeToken});
}
});
Backbone Model Class
var PaymentChargeModel = Backbone.Model.extend({
url: function(){
return '/api/paymentcharge';
},
defaults: {
}
})
Setup/Call the View from header menu event
if (!this.paymentPanelView) {
this.paymentPanelView = new PaymentPanelView({model: new PaymentChargeModel()});
}
$('#content').html(this.paymentPanelView.el);
this.paymentPanelView.delegateEvents();
this.selectMenuItem('payment-menu');
I think the problem has to do with your View's el and the event you are listening for.
You never explicitly define your View's el, which means it gets initialized to a detached <div> element. You then use your template to fill that <div> with the form element from the template. Even though your <div> is detached, you get to see the content, because you add the content of you el to #content using jquery.
I think the problem is that you are listening for a submit event on the <div> in your el, not the contained <form>. Try changing your events hash to this:
events: {
'submit form#stripepaymentform': 'paymentcharge'
}
Basically, listen for events on the contained element like in jquery's .on. You can also go right to a button click, something like this:
'click #mysubmitbutton': 'paymentcharge'
Hope this helps!

Knockout mapping plugin does not handle hierarchical data properly

I have hierarchical JSON structure that differs after every new JSON from the server side. Given my template, this does not adequately show model update.
After troubleshooting, I noticed the mapping plugin does not correctly map child elements(or perhaps I am doing it incorrectly)
I can also track the memory keeps growing for every update in the datamodel.
Any help will be greatly appreciated.
This simple test is up on JSFiddle http://jsfiddle.net/Bru5a/1/
Here is my view
<div id="view">
The behavior is different depending on the order you load the model.
First
Second
Third
<span data-bind="text: name"></span>
<div data-bind="if: $data.child">
<b data-bind="text: child.name"></b>
<div data-bind="if: child.sub">
<b data-bind="text: child.sub.name"></b>
</div>
</div>
</div>
Here is my Javascript:
var BaseModel = function(om) {
ko.mapping.fromJS(om, {}, this);
};
var resourceModel = null;
function applyJson(json) {
try {
if(resourceModel){
ko.mapping.fromJS(json, {} ,resourceModel);
} else {
resourceModel = new BaseModel(json);
ko.applyBindings(resourceModel, $("#view")[0]);
}
} catch(e) {
alert(e);
}
}
function loadFirst() {
var json = { "name" : "1",
"child" : {
"name": "Child One"
}
};
applyJson(json);
}
function loadSecond() {
var json = { "name" : "2" };
applyJson(json);
}
function loadThird() {
var json = { "name" : "3",
"child" : {
"name": "Child Three",
"sub" : {
"name" : "Third Sub Child"
}
}
};
applyJson(json);
}
$(document).ready(function () {
$("#second").click(function(){
loadSecond();
});
$("#third").click(function(){
loadThird();
});
$("#first").click(function(){
loadFirst();
});
});​
What is happening in your case, is that knockout is behaving as designed.
To see what is happening, add the following line inside your outer div
<div data-bind="text: ko.toJSON($root)"></div>
You can see what is being bound in your view model.
To understand what is being displayed, Watch what is happening the to the viewmodel as you select the different links. As you update your model, you will see that once a property has been created, it remains there. This is by design of how the mapper works.
Next, you have to remember that ko.applyBindings is only being called ONE time. Therefore, the binding are only being applied one time to the properties that are in existence at the time the applyBindings is called. When you add properties to your viewmodel later, they will not automatically be bound to the data-bindings.
To make this example work, you will need to re-think your view model so that all the properties are present at the time you call apply bindings.
EDIT
I've edited your fiddle to show what I was talking about at http://jsfiddle.net/photo_tom/Bru5a/5/

When to call YUI destroy?

When should destroy be called? Does it ever get called automatically by YUI lifecycle? Does the page unload cause the YUI lifecycle to call destroy on all objects created during the page processing? I have been working under the assumption that I need to make all my own calls to destroy but that gets hairy when ajax calls replace sections of code that I had progressively enhanced. For example:
<div id="replaceMe">
<table>
<tr>
<td>1</td>
</tr>
<tr>
<td>2</td>
</tr>
</table>
<script>
YUI().use('my-lib', function(Y) {
Y.mypackage.enhanceTable("replaceMe");
});
<script>
</div>
The my-lib module basically adds a click handler and mouseover for each row:
YUI.add('my-lib', function(Y) {
function EnhancedTable(config) {
EnhancedTable.superclass.constructor.apply(this, arguments);
}
EnhancedTable.NAME = "enhanced-table";
EnhancedTable.ATTRS = {
containerId : {},
onClickHandler : {},
onMouseoverHandler : {},
onMouseoutHandler : {}
};
Y.extend(EnhancedTable, Y.Base, {
_click : function(e) {
//... submit action
},
destructor : function() {
var onClickHandler = this.get("onClickHandler"),
onMouseoverHandler = this.get("onMouseoverHandler"),
onMouseoutHandler = this.get("onMouseoutHandler");
onClickHandler && onClickHandler.detach();
onMouseoverHandler && onMouseoverHandler.detach();
onMouseoutHandler && onMouseoutHandler.detach();
},
initializer : function(config) {
var container = Y.one("[id=" + this.get("containerId") + "]");
this.set("container", container);
this.set("onMouseoverHandler", container.delegate("mouseover",
this._mouseover, "tr", this ));
this.set("onMouseoutHandler", container.delegate("mouseout",
this._mouseout, "tr", this ));
this.set("onClickHandler", container.delegate("click",
this._click, "tr", this ));
},
_mouseout : function(e) {
e.currentTarget.removeClass("indicated");
},
_mouseover : function(e) {
e.currentTarget.addClass("indicated");
}
});
Y.namespace("mypackage");
Y.mypackage.enhanceTable = function(containerId) {
var enhancedTable new EnhancedTable({containerId:containerId});
};
}, '0.0.1', {
requires : [ 'base', 'node' ]
});
The click handler would submit a request back to my application that would change the page. Do I need to remember all the enhancedTable objects and have an onunload handler call the destroy method of each? Or does the YUI framework take care of this?
The last part of this quesiton is, I also have code outside of this that replaces the whole table by replacing the content of the <div id="replaceMe">. In doing so, the script would get re-run and augment the new <table> with a new EnhancedTable. Do I need to remember the old table, and destroy it before the new table clobbers it?
Instead of setting handlers as attributes I'd store them all in an array like this:
this._handlers = [
container.delegate("mouseover", this._mouseover, "tr", this ),
container.delegate("mouseout", this._mouseout, "tr", this ),
container.delegate("click", this._click, "tr", this )
];
Then add a destructor method that does the following
destructor : function() {
new Y.EventTarget(this._handlers).detach();
}
It accomplishes the same thing but with way less work on your part!
Ideally instead of running this against each table you'd attach all your delegates to #replaceMe so that it wouldn't need to be recreated each time you changed the content, no matter where that happened from.
YUI won't automatically call .destroy() for you on unload, it will clean up DOM subs though. The above is extra credit that's really only necessary if you are going to be destroying the object yourself.

Resources