Detect multiple keypress in Backbone - backbone.js

I am trying to catch e keypress event like Alt + g, my backbone code is something like this right now:
class MyView extends Backbone.View
template: ...
events:
"keydown input" : "logKey"
logKey: (e) ->
if e.keyCode == 18 and e.keyCode == 71
console.log('did it!')
Which doesnt work, as there is only one event keycode at a time.
How could this be achieved? Thanks!

Why not look for keypress instead of keydown? Something like this:
class MyView extends Backbone.View
events:
"keypress input" : "logKey"
logKey: (e) ->
console.log('did it') if(e.keyCode == 169)
Demo: http://jsfiddle.net/ambiguous/fmr8D/

You'll have to set a separate variable to keep track of modifier keys and check for that on your keydown events. Like:
events:
"keydown input" : "logKeyDown",
"keyup input" : "logKeyUp"
logKey: (e) ->
if e.keyCode == 18
altDown = true
if altDown && e.keyCode == 71
console.log('did it!')
logKeyUp: (e) ->
if e.keyCode == 18
altDown = false

Related

Trigger other key rather than original key using angularjs

I am try to trigger " ` " keyCode = 192 when I press " enter " keyCode = 13. I am trying below code but it is not working in contenteditable div. Any idea?
And how to $apply this?
$scope.pressKey = function(event){
if(event.keyCode == 13){
event.preventDefault();
var e=angular.element.Event('keydown');
console.log(e);
e.which=192;
$('#regularDot').trigger(e);
}
<div id="regularDot" ng-keypress="pressKey($event)" class="wf-loading"
ng-model="regularDot" contenteditable="true" n></div>
Don't use pure JS methods like KeyboardEvent() it has cross browser support issues, use jQuery instead.
Now angular.element has basic support of jquery but it does not support Event() method which you used. So best approach is having jquery library in your codebase (with its script tag attached before angularjs in index.html). Then change your code to as follows:
$scope.pressKey = function(event) {
if (event.keyCode == 13) {
event.preventDefault();
var e = jQuery.Event('keypress');
console.log(e);
e.which = 192;
e.keyCode = 192;
$timeout(function() {
$('#regularDot').trigger(e);
});
} else if(event.keyCode == 192){
console.log("Newly triggered event catched with keyCode " + event.keyCode);
}
}
Here I've made just few changes like adding trigger method inside $timeout so that it'll wait small time to complete the preventDefault of previously triggered event before setting (triggering) new event, and doing $apply also. I've changed newly triggered event type to keypress instead of keydown so that after triggering event you'll be able to handle it using ng-keypress on that element (with id regularDot).
Similar plunker example to refer.

prevent expanding parent node when its datasource is updated due to addition of a child item inside kendo treeview

I have a kendotreeview with 3 root parent nodes.Example is shown below.
When I drop child3 into New SubGroup, the node "New Subgroup" gets expanded by default even if it was collapsed before. I would like to prevent this possibility. If New SubGroup was expanded before, then I would like to keep it as it is. The problem is that the expand gets called before the databound event and hence I am stuck here.
Please help.
parent1:
--New SubGroup
--Child2
--Child3
--Child4
parent2:
--Child4
--Child5
Code snippet:
dataBound: function (e) {
console.log("DataBound", e.node);
var nodedataitem = $("#DimMeasTree").data("kendoTreeView").dataItem($(e.node));
if (nodedataitem.FieldKey === "SubGroup" && ($(e.node).attr("aria-expanded")) === "true") {
$("#DimMeasTree").data("kendoTreeView").collapse($(e.node));
}
}
I am subscribing to my own custom expand function (i.e. subgroup_expand()) after I initialize my treeview. It is as demonstrated below:
<div id="treeview"></div>
<script>
function subgroup_expand(e) {
if (typeof event === 'undefined') {
//If browser is Firefox, the subgroup will expand and do not close automatically.
// It is because Firefox does not support "event" attribute gloabally as in IE or in Google chrome.
}
else if (!!e.node && typeof(event) !== 'undefined' && event.type !== "click" && event.type !== "dblclick") {
var nodedataitem = $("#treeview").data("kendoTreeView").dataItem($(e.node));
if (nodedataitem.FieldKey === "SubGroup") {
// e.preventDefault();
setTimeout(function () {
//Collapse the subgroup if it was not expanded by click or dblclick.
$("#treeview").data("kendoTreeView").collapse($(e.node));
}, 50);
}
}
}
$("#treeview").kendoTreeView({
dataSource: modeldata
});
var treeview = $("#treeview").data("kendoTreeView");
treeview.bind("expand", subgroup_expand);
</script>

How to enable carriage return with shift+return only

I'm using a textarea in a simple chat app. I'd like to enable the carriage return only when the user hits shift+return, and submit the form when the user hits the return key alone.
I'm using the ngKeydown directive. The problem is when I hit enter, the message is sent ok, the textarea is cleared and after that, a carriage return si inserted. It means the event keeps propagate...
Here is the HTML code:
<textarea ng-model="messageTyped" ng-keydown="checkReturn($event)"></textarea>
and here is the angularjs code:
function chatController($scope, ChatService) {
$scope.messages = ChatService.messages
$scope.checkReturn = function(event) {
if (event.keyCode == 13 && !event.shiftKey) {
event.stopPropagation() // <------ this line seems to have no effect
// submit the message:
if ($scope.messageTyped) {
ChatService.SendMessage($scope.messageTyped)
$scope.messageTyped = ""
}
}
}
}
I don't know what I'm missing... Thanks for your help !
I would suggest writing a custom directive for this. Then you could reuse it for any elements you'd like. Here is an example of using it to move to the next input element. Just put enter-next in whatever element you want to have this ability.
.directive('enterNext', function() {
return {
restrict: 'A',
link: function($scope,elem,attrs) {
elem.bind('keydown', function(e) {
var code = e.keyCode || e.which;
if ((code === 13) && (e.shiftKey)) {
e.preventDefault();
elem.nextAll('input').first().focus();
}
});
}
}
});
it can be done using ng-keyup and without any directive:
<textarea ng-keyup="$event.keyCode === 13 && (!$event.shiftKey) && TARGET_FUNCTION()"></textarea>

How to get trigger to listen properly

I am having a hard time getting my trigger to respond properly. I have plenty that are working but one of them isn't and I can't understand why.
Here is my AppController class
class ProjectOrder.View.AppController extends Backbone.View
initialize: ->
#promptOfficeSearch()
promptOfficeSearch: ->
officeSearch = new ProjectOrder.View.OfficeSearch
officeSearch.on 'createOffice', #promptOfficeCreate
officeSearch.on 'createTicket', #promptTicketCreate
officeSearch.on 'accountAndTicketExist', #killProcessAccountExists
promptOfficeCreate: (serial) ->
#officeModel = new ProjectOrder.Model.OfficeModel()
#officeModel.set('serial_number', serial)
officeCreate = new ProjectOrder.View.OfficeCreator({model: #officeModel})
officeCreate.on 'createTicketOffAccount', #promptTicketCreate
promptTicketCreate: (model) ->
console.log 'promptTicketCreate'
model = model || #officeModel
ticketModel = new ProjectOrder.Model.TicketModel()
new ProjectOrder.View.TicketCreator({ticketModel: ticketModel, officeModel: model})
killProcessAccountExists: (ticket_id) ->
msg = document.createElement 'div'
msg.className = 'account-exists-msg'
msg.innerHTML = "Account already exists. Redirecting to ticket #{ticket_id}..."
$('#create-order-div').append(msg)
setTimeout((->
window.location = "/pto/#{ticket_id}"
), 2000)
All of the triggers from the officeSearch object in the promptOfficeSearch function work properly. They are all triggered as follows, respectively:
#trigger 'createOffice', serial
#trigger 'createTicket', data.model[0]
#trigger 'accountAndTicketExist', data.model
But with the officeCreate object in the promptOfficeCreate, it does not respond to the createTicketOffAccount event which is registered in the submitOffice ajax success callback in my OfficeCreator class:
class ProjectOrder.View.OfficeCreator extends Backbone.View
template: _.template($("#OfficeCreator").html())
id: 'office-creator'
events:
'click .submit' : 'submitOffice'
initialize: ->
#render()
render: ->
#$el.html(#template(#model.toJSON()))
$('#create-order-div').append(#$el)
submitOffice: ->
#setModelData()
#model.save(null,{
success: (model) =>
#trigger 'createTicketOffAccount', model
##$el.remove()
error: ->
alert 'error'
})
setModelData: ->
#model.set({
office_name: $('#office').val()
doctor_name: $('#doctor').val()
emr: $('#has-emr').is(':checked')
forms_builder: $('#has-forms').is(':checked')
iehr: $('#has-iehr').is(':checked')
clipboard: $('#has-clip').is(':checked')
specialty_id: $('#specialty').val()
})
any ideas why my trigger is not working?
I think you need fat arrows on all the methods in your AppController class.
When this event fires:
officeSearch.on 'createOffice', #promptOfficeCreate
the promptOfficeCreate function gets invoked as a normal function as opposed to a method bound to your controller instance as this, so when this happens:
officeCreate.on 'createTicketOffAccount', #promptTicketCreate
#promptTicketCreate is undefined and the event binding doesn't wire up properly.

Passing functions to the `events` hash

Inside Backbone.View instances one can set an events hash of callbacks:
events: { 'click #element' : 'myFunction' }
When the function I try to access is not a direct function of the view instance (e.g. this.model.myFunction) I cannot pass the function right in the events hash. I have tried:
events: { 'click #element' : 'model.myFunction' }
and
events: { 'click #element' : this.model.myFunction }
How can I tell my backbone view to use this.model.myFunction as a callback right from the events hash?
No, you can't do that. The relevant chunk of Backbone looks like this:
delegateEvents : function(events) {
if (!(events || (events = getValue(this, 'events')))) return;
this.undelegateEvents();
for (var key in events) {
var method = this[events[key]];
if (!method) throw new Error('Event "' + events[key] + '" does not exist');
//...
So the values in events have to be the names of methods in your view object. You could route the events yourself though:
events: { 'click #element': 'myFunction' },
// ...
myFunction: function(e) {
this.model.myFunction(e);
}

Resources