Backbone.ModelBinder: why do I have to hit submit twice? - backbone.js

I am using Backbone and Backbone.ModelBinder.
I have a bunch of text fields that are bound via BackboneModelBinder. Everything works as expected however when I make a change to a text field and I don't unfocus the field first (click off the input field) before hitting the SAVE button, I have to hit the Save button twice -- once to unfocus the fields, and then a second time to actually fire the save button handler (which should have fired the first time)
(Save is a standard html button with a backbone event bound to it).
Does anyone have any knowledge of why this might be?
I hope this made sense :|
Thanks for any help or direction
-Kirk

That's because ModelBinder by default set the new value to the model's attributes on "blur" or "change" events (it dependes on the input's type). You can modify this behavior by changing the source code, adding keyup as binding event in those two methods:
_bindViewToModel:function () {
$(this._rootEl).delegate('', 'change keyup', this._onElChanged);
// The change event doesn't work properly for contenteditable elements - but blur does
$(this._rootEl).delegate('[contenteditable]', 'blur keyup', this._onElChanged);
},
_unbindViewToModel: function(){
if(this._rootEl){
$(this._rootEl).undelegate('', 'change keyup', this._onElChanged);
$(this._rootEl).undelegate('[contenteditable]', 'blur keyup', this._onElChanged);
}
},

Related

AngularJS ng-class Expression Not Updating Properly

So I'm trying to build a custom autocomplete dropdown for a text input. To do it, I am listening for the keydown event and if it's an up or down arrow press, I'm setting a $scope.arrowSelectedItem variable to the proper one in the list. (As a side note, all the functionality works as far as selecting an item from the list that pops up. All I'm trying to do is highlight the current one that they've marked with the up/down arrows).
On the markup side, the items in the autocomplete list are output with ng-repeat, with ng-repeat="item in itemList". The ng-class expression I'm using is ng-class="{highlighted: item === arrowSelectedItem}". I know that the $scope.arrowSelectedItem is being updated on each arrow press by using console.log, but for some reason the class isn't being updated to the list item properly.
What I've found is that after the first time of hitting an arrow key, if I make the text input box lose focus, then the class is added. Then if I click back in the box, move the arrow to select a different item, click out of the input box, then click back in, the class is added to the new one. I know that sounds weird, but that's what I've found.
What I'm not sure about is why the ng-class expression isn't being evaluated on every arrow key press. Does anyone have any ideas why?
The answer here is that "raw" DOM events which fire outside of one of angular's built in directives (such as click events via ng-click etc) will not trigger a $digest cycle update. Until this happens the $scope properties will not be updated.
If you are in a position where you are listening for DOM events by using another framework, or simply using addEventListener(), you will need to let angular know about any changes by using $scope.$apply(), or by wrapping the code in a $timeout().
If you do this in your event handler, angular will trigger a new $digest cycle update for every keypress and your new scope values will propagate to the view.

How to Get keypress event in extjs charts

This is related to ExtJs 4.2 Charts.
I am stuck where i need to make selection of multiple columns in a column chart only when a user press ctrl key + column selection with mouse click. So, i couldn't find how to capture control key press event in itemclick event of chart.
Please send in your suggestions...
This is a shot at a direction you might take and not a definitive answer.
You might look at adding a couple listeners to the Panel or Viewport you are working with, add a keydown event and the keyup event, not sure if that will work, you might go so far as to add it to the DOM models window too. You see the problem I am seeing here is that you have to have focus first on something, and you will probably at least have the focus of the window, where if you, put this listener on the actual chart you have to focus there by clicking on the chart first and then selecting the key and then clicking again, kind of a lot of actions I would think and not intuitive.
Then set a global variable to true on the key press down and back to false on the key press up.
Then in the itemmousedown event that you also create on the charts Series so you can read the variable and use it as you intend.
here is what the listener should look like
series: [{
type: 'column',
...
listeners: {
itemmousedown: function(item, eOpts) {
.... // get your global variable here.
console.log(item);
console.log(eOpts);
}
},
I found a solution it is working fine but its a kind of workaround.
Here is the code snippet...
var bIsControlkeyPressed=false;
function setCtrlKey(event){
if (event.ctrlKey) {
bIsControlkeyPressed=true;
}else{
bIsControlkeyPressed=false;
}
alert(bIsControlkeyPressed)
}
<body onmousedown = "setCtrlKey(event)">hello</body>
When you click anywhere on page (body part i.e. 'hello' in this case), this code will set the global flag to true if ctrl key is also pressed else false is set. I know there are other ways this can be done but this approach works with IE8 also :)

Click event not firing with Backbone & jQuery

I'm using Backbone in an app & running into an situation where events are not firing.
My View, maps to a dialog interface containing several controls (a text area, a couple radio buttons, etc.) and a save button. I'm defining the following events:
events: {
'input': 'onchange',
'change': 'onchange',
'click .save': 'save',
'click .cancel': 'cancel',
},
Each time any form element in the dialog changes, I fire onchange, which performs some validation and either enables or disables the save button.
In the 'normal' flow, everything works properly. I fill out the textarea, click an option on the radio button, and then click save. My work is saved properly.
In an alternative flow, I try to click save while my cursor is still in the text area, and nothing happens. Then, if I click on the save button a second time, the form saves correctly. I've tried setting a breakpoint at the very beginning of the save method, and confirmed that it is not called during the first button click, and is then called correctly with the second button click.
I've tried to make a minimal example as a jsFiddle to demonstrate the issue, but I can't isolate the buggy behavior.
What could be preventing the click event and save function the first time I click the button? Do you have any tips or recommendations for helping debug an issue like this?
Update: Using a Javascript Profiler
I went back and used a profiler to dig in on what's happening. Here was my process:
Set up page for test, with everything filled in except the primary textarea
Start profiler
Type a letter into the textarea and wait for onchange handlers to fire, which is evidenced by Save button becoming enabled
Wait several seconds
Click Save - nothing happens
Stop profiler
And here's my profile:
What's interesting is that there's a clear flurry of activity when the onchange handlers fire, seen as a visible spike in the flame chart. However, when I click save the first time, there is no javascript execution captured at all! Very curious...

Autosaving on blur + "Undo" button

I am writing directive, that will act like this:
allow editing of some text (using content editable)
on loosing focus it should save its value to model (lately watched and saved to DB)
there should be button "Undo" which revert changes.
My implementation is: http://plnkr.co/edit/DsWEYQV4j51i4GO6KjSe?p=preview
The only problem I have is when I press "undo" button, DIV lose focus (so 'focusout' event is fired) and value is saved in model, so "undo" button can't revert its value.
( I click "undo" -> focusout event (autosave) -> click event (??? can't revert) )
Possible workarounds I see:
set timeout on blur and cancel it if 'undo' button was pressed. But it is ugly as user can enter value and navigate to other part of app, so timeouted saving won't run any $watch listeners.
save value on focusin and restore it when 'undo' button is saved. This cause another problem: $watch listeners would run with changed value and then run again with previous value (so there would be 2 writes to DB instead of one)
Do anybody have solution for such behaviour (autosave on blur + undobutton)?
How about using underscore.js debounce function or similar to cause a delay on autosave, where it will check for a undo flag and cancel? Not sure what the $watch listeners are doing. Of course it will still not work if the user completely goes out of the app or refreshes the page etc.

ExtJS: focus field

I have a window containing a form (formPanel). Users can show this window clicking on a button in an ExtJS environment. I would like that when the user clicks the button to show the window, a specific field inside the form contained by the window will focus (by this I mean that the cursor should move to that field so that the user can insert data without needing to click on the field itself first).
I tried some solutions, but could not get them work. Any hints?
Here is what I tried, using some examples I found... but it does not work as expected. This function() is called by the ExtJS button in my interface:
function openCardForm(IDUser){
//Reset the value of this field which may be still there from the prev. usage
Ext.getCmp('assignFormCARDNUMBER').reset();
formAssignCard.getForm().load({
url: 'gen/jsonUser.php',
params:{IDUser:IDUser},
waitMsg: 'Loading...'
});
//Try to focus the Card field when rendering the form
Ext.getCmp('assignFormCARDNUMBER').on("render",function(){
Ext.getCmp('assignFormCARDNUMBER').focus(true,10);
});
win.show();
}
try on show instead.
Or Use
defaultButton : yourComponentToFocusOn
A bit confusing but the defaultButton can be any component (not necessary to be an actual button)
You can also try setting the tabindex of the field to zero in its config options...that way you wont even need to add a listener to detect the show event.
ie:
tabIndex:0

Resources