Backbone.modelBinder - unable to bind on 'keypress' - backbone.js

I am using Backbone.ModelBinder to my application. I would like to add the event listener on keyup on my name field. I tried this way..
$().ready(function () {
dogs = new Backbone.Collection({model:Backbone.Model});
var nameConverter = function(direction, value){
console.log(direction, value); //on keyup nothing consoles.
return value;
}
var phoneConverter = function (direction, value) {
if (direction === Backbone.ModelBinder.Constants.ModelToView) {
var formattedPhone = '';
if (value) {
formattedPhone = value.replace(/[^0-9]/g, '');
if (formattedPhone.length == 7) {
formattedPhone = formattedPhone.substring(0, 3) + '-' + formattedPhone.substring(3, 7);
}
else if (formattedPhone.length == 10) {
formattedPhone = '(' + formattedPhone.substring(0, 3) + ') ' + formattedPhone.substring(3, 6) + '-' + formattedPhone.substring(6, 10);
}
else if (formattedPhone.length == 11 && formattedPhone[0] === '1') {
formattedPhone = '1 (' + formattedPhone.substring(1, 4) + ') ' + formattedPhone.substring(4, 7) + '-' + formattedPhone.substring(7, 11);
}
}
return formattedPhone;
}
else {
return value.replace(/[^0-9]/g, '');
}
};
model = new Backbone.Model({firstName:'Bob', graduated:'maybe', phone: '1234567'});
model.bind('change', function () {
$('#modelData').html(JSON.stringify(model.toJSON()));
});
model.trigger('keyup'); // just to show the #modelData values initially, not needed for the ModelBinder
ViewClass = Backbone.View.extend({
_modelBinder:undefined,
initialize:function () {
this._modelBinder = new Backbone.ModelBinder();
},
render:function () {
var html = '\
Edit your information:<br><br>\
First Name: <input type="text" name="firstName"/><br>\
Last Name: <input type="text" name="lastName"/><br>\
Phone: <input type="text" name="phone"/><br>\
Height: <input type="text" name="height"/><br><br>\
\
Graduated: Yes: <input type="radio" id="graduated_yes" name="graduated" value="yes">\
No: <input type="radio" id="graduated_no" name="graduated" value="no">\
Maybe: <input type="radio" id="graduated_maybe" name="graduated" value="maybe"><br>\
\
Eye Color: Green: <input type="radio" name="eyeColor" value="green">\
Blue: <input type="radio" name="eyeColor" value="blue">\
Brown: <input type="radio" name="eyeColor" value="brown"><br><br>\
\
Drivers licence: <input type="checkbox" name="driversLicense"/><br>\
Motorcycle license: <input type="checkbox" name="motorcycle_license" /><br><br>\
Dog: \
<select name="dog">\
<option value="">Please Select</option>\
<option value="1">Andy</option>\
<option value="2">Biff</option>\
<option value="3">Candy</option>\
</select> <br><br>\
Big Text:<br> <textarea name="bigText" rows="4" cols="80"></textarea>\
';
this.$el.html(html);
var bindings = {
firstName: {selector:'[name=firstName]',converter:nameConverter},
lastName: '[name=lastName]',
driversLicense:'[name=driversLicense]',
motorcycle_license:'[name=motorcycle_license]',
graduated:'[name=graduated]',
eyeColor:'[name=eyeColor]',
phone:{selector:'[name=phone]', converter:phoneConverter},
dog:{selector:'[name=dog]', converter:(new Backbone.ModelBinder.CollectionConverter(dogs)).convert},
bigText:'[name=bigText]'
};
//this._modelBinder.bind(this.model, this.el, bindings);
this._modelBinder.bind(this.model, this.el, bindings, {changeTriggers: {'': 'change', '[name=firstName]': 'keyup'}});
return this;
}
});
view = new ViewClass({model:model});
$('#viewContent').append(view.render().el);
});
but not working. any one correct me please?
Here is the live Demo

You want to make use of custom triggers. It is not avliable in the version you are using but is avaliable in 1.0.5,
the only thing you would then need to add is a call to bind input on your text field
this._modelBinder.bindCustomTriggers(this.model, this.el,"input input.[name=firstName]" , bindings, {changeTriggers: {'':'change', 'input.[name=firstName]':'input'}});
here it is in a demo working with ModelBinder 1.0.5

Related

dropdown values load sometimes and sometimes not in angularjs

I am working on angularjs , where I am loading dropdowns from database in angularjs controller. I am facing an intermittent issue that sometimes dropdown values load and sometimes don't . Its working on my local but when I upload on server this intermittent issue is coming.
I have even tried to use ng-init on html and then put login there in that function but still this issue is there.
here is html
<div class="x_panel" ng-init="loadDropDownData()">
<div class="x_title">
<h2 id="EditjobTitle" style="display:none">Edit Job<small></small></h2>
<button class="btn col-md-offset-9" id="btnBack" style="display:none" ng-click="Cancel()">Back</button>
<h2 id="NewjobTitle">New Engagement<small></small></h2>
<div class="clearfix"></div>
</div>
<div class="x_content">
<br>
<form name="JobForm" id="demo-form2" data-parsley-validate="" class="form-horizontal form-label-left" novalidate="">
<div class="form-group">
<div class="col-md-6 col-sm-6 col-xs-12 col-md-offset-3 save-buttons">
<button type="submit" class="btn btn-success" ng-click="JobForm.$valid && save()">Save</button>
<button class="btn" ng-click="Cancel()">Cancel</button>
</div>
</div>
<h5>Job Data</h5>
<input type="hidden" id="JobID" ng_value="{{Job.JobNum}}">
<div class="form-group">
#Html.Label("Job Name", new { #class = "control-label control-label-j col-md-2 col-sm-3 col-xs-12" })
<div class="col-md-3 col-sm-3 col-xs-12">
<input type="text" name="JobName" ng-model="Job.JobName" ng-minlength="4" id="txtJobName" class="form-control col-md-7 col-xs-12" required="" maxlength=25>
</div>
#Html.Label("EngType", new { #class = "control-label control-label-j col-md-2 col-sm-3 col-xs-12" })
<div class="col-md-3 col-sm-3 col-xs-12">
<select name="EngType" ng-model="Job.EngType" ng-options="s.ID as s.EngTypes for s in Job.lstEngType" class="form-control col-md-7 col-xs-12" required="">
<option value="">-- Select EngType --</option>
</select>
</div>
</div>
</form>
</div>
</div>
and Js file is as below
app.controller('AddJobController', function ($scope, $location, $filter, ShareData, jobService, $compile) {
$scope.phoneNumbr = /^\+?\d{3}[- ]?\d{3}[- ]?\d{4}$/;
$scope.datePattern = /^[0-9]{2}\/[0-9]{2}\/[0-9]{4}$/i
$scope.regEx = "/^[0-9]{10,10}$/;";
$scope.listOfStatus = [];
$scope.showStatusError = false;
$scope.statusText = "";
$scope.loadDropDownData = function() {
loadJobInitdata();
}
$(document).ready(function () {
$("#txtCloseDate").datepicker({ format: 'mm/dd/yyyy' });
$("#txtDraft_Date").datepicker({ format: 'mm/dd/yyyy' });
$("#txtFinal_Date").datepicker({ format: 'mm/dd/yyyy' });
$("#txtOpenDate").datepicker({ format: 'mm/dd/yyyy' });
$("#txtFinalSent").datepicker({ format: 'mm/dd/yyyy' });
$('body').off('click', '.remove-record').on('click', '.remove-record', function () {
removeSpan = "";
var addButton = "<div class='col-md-3 col-sm-3 col-xs-12'>\
<input type='button' class='btn btnAddDeadline' value='Add Deadline' />\
</div>";
var ifAdd = false;
if ($(this).parent().find('.btnAddDeadline').length == 1) {
ifAdd = true;
}
if ($scope.Job.JobNum != null && $scope.Job.JobNum != undefined) {
var ID = $(this).parent().find('.deadline-datepicker').attr('id')
ID = ID.replace("Date", "");
var removeSpanElement = $(this);
if (ID != "txtDeadlines") {
var promiseDeleteDeadline = jobService.DeleteDeadline(ID)
promiseDeleteDeadline.then(function () {
removeSpanElement.parent().remove();
if (ifAdd) {
PopulateDeadline(null, addButton, removeSpan);
$('.deadline-datepicker').datepicker({
ignoreReadonly: true,
startDate: new Date()
});
}
})
}
else {
$(this).parent().remove();
if (ifAdd) {
PopulateDeadline(null, addButton, removeSpan);
$('.deadline-datepicker').datepicker({
ignoreReadonly: true,
startDate: new Date()
});
}
}
}
else {
$(this).parent().remove();
if (ifAdd) {
PopulateDeadline(null, addButton, removeSpan);
$('.deadline-datepicker').datepicker({
ignoreReadonly: true,
startDate: new Date()
});
}
}
});
})
if (ShareData.value == 0) {
//loadJobInitdata();
}
else {
Edit();
}
$scope.maxlength = 3;
$scope.Job = [];
function Edit() {
if (!ShareData.createAsNewJob) {
$('#NewjobTitle').hide();
$('#EditjobTitle').show();
$('#btnBack').show();
}
//loadJobInitdata();
var promiseEditjobData = jobService.EditJob(ShareData.value);
promiseEditjobData.then(function (jobdata) {
GetDeadlinesbyJobID(ShareData.value);
getStatusCommentsJobId(ShareData.value);
$scope.Job = jobdata.data;
var CloseDate = $scope.Job.CloseDate = (jobdata.data.CloseDate != null && jobdata.data.CloseDate != undefined) ? $filter('date')(new Date(jobdata.data.CloseDate), 'MM/dd/yyyy') : null
var OpenDate = $scope.Job.OpenDate = jobdata.data.OpenDate = (jobdata.data.OpenDate != null && jobdata.data.OpenDate != undefined) ? $filter('date')(new Date(jobdata.data.OpenDate), 'MM/dd/yyyy') : null
var Draft_Date = $scope.Job.Draft_Date = jobdata.data.Draft_Date = (jobdata.data.Draft_Date != null && jobdata.data.Draft_Date != undefined) ? $filter('date')(new Date(jobdata.data.Draft_Date), 'MM/dd/yyyy') : null
var Final_Date = $scope.Job.Final_Date = jobdata.data.Final_Date = (jobdata.data.Final_Date != null && jobdata.data.Final_Date != undefined) ? $filter('date')(new Date(jobdata.data.Final_Date), 'MM/dd/yyyy') : null
$scope.Job.Deadlines = jobdata.data.Deadlines = (jobdata.data.Deadlines != null && jobdata.data.Deadlines != undefined) ? $filter('date')(new Date(jobdata.data.Deadlines), 'MM/dd/yyyy') : null
console.log(new Date(CloseDate));
var myDate = new Date(1978, 2, 11)
if (CloseDate != null) { $("#txtCloseDate").datepicker("update", new Date(CloseDate)); }
if (OpenDate != null) { $("#txtOpenDate").datepicker("update", new Date(OpenDate)); }
if (Draft_Date != null) { $("#txtDraft_Date").datepicker("update", new Date(Draft_Date)); }
if (Final_Date != null) { $("#txtFinal_Date").datepicker("update", new Date(Final_Date)); }
ShareData.value = 0;
if (ShareData.createAsNewJob == true) {
$scope.Job.JobNum = null;
ShareData.createAsNewJob = false;
}
},
function (errorPl) {
$scope.error = errorPl;
ShareData.value = 0;
alert($scope.error);
});
}
function loadJobInitdata() {
var promiseLoadDLLs = jobService.GetJobInitData();
promiseLoadDLLs.then(function (pl) {
//$scope.Job = pl.data
$scope.Job.lstEngType = pl.data.lstEngType,
$scope.Job.lstWorkProduct = pl.data.lstWorkProduct,
$scope.Job.lstNAICSCode = pl.data.lstNAICSCode,
$scope.Job.lstSubject = pl.data.lstSubject,
$scope.Job.lstManager = pl.data.lstManager,
$scope.Job.lstClientType = pl.data.lstClientType,
$scope.Job.lstFeeBasis = pl.data.lstFeeBasis,
$scope.Job.lstBillingCycle = pl.data.lstBillingCycle,
$scope.Job.lstExpenses = pl.data.lstExpenses,
$scope.Job.lstSalesperson = pl.data.lstSalesperson,
$scope.Job.lstPriority = pl.data.lstPriority,
$scope.Job.lstStaff = pl.data.lstStaff,
$scope.Job.lstLogo_in_Client_Logo_File = pl.data.lstLogo_in_Client_Logo_File,
$scope.Job.lstTombstone_Status = pl.data.lstTombstone_Status
},
function (errorPl) {
$scope.error = errorPl;
alert($scope.error);
});
}
$scope.Cancel = function () {
$location.path(ShareData.page);
}
$scope.AddDeadline = AddDeadline;
});

oninput not working in Angular. Alternative?

Im trying to create a function that reads the value of an input and triggers a series of true/false, however the code below keeps returning "passStrength is not defined."
From what I can find, oninput isn't supported by Angular. How can achieve this in Angular?
Within my controller:
$scope.passStrength = function(input) {
if (input.value.toLowerCase().indexOf(/[a-z]/) > -1) {
$scope.lwrChar = true;
console.log('lower ' + $scope.lwrChar);
} else if (input.value.toUpperCase().indexOf(/[A-Z]/) > -1) {
$scope.uprChar = true;
console.log('upper ' + $scope.uprChar);
} else if (input.value.indexOf() == !isNaN(n)) {
$scope.nbrChar = true;
console.log('number ' + $scope.nbrChar);
} else if (input.value.length >= 8) {
$scope.countChar = true;
console.log('count ' + $scope.countChar);
}
};
and in my markup:
<input id="password" oninput="passStrength()" />
To fire an event when the input changes, use ng-change. Also, you must define a ng-model.
<input ng-model="password" ng-change="passStrength(password)" />
Edit:
Created a plunker demonstrating it

Angular ng-if + function not work

In this first code when I change the anoini, the gerar() function show the old value.
But, when I remove <div ng-if.... works fine.
do you knows what's wrong ?
Tks
// JavaScript Document
var app = angular.module('dadosHist', []);
app.controller('dadosHistCtrl', function($scope) {
$scope.mesini = 1; $scope.anoini = 2011;
$scope.mesfim = 7; $scope.anofim = 2015;
$scope.log = "";
$scope.escolherperiodo = true;
$scope.gerar = function() {
this.log = this.anoini;
meses = ((this.anofim - this.anoini) * 12) + (12 - this.mesini) + this.mesfim;
qtdLoop = arrEstacoes.length * meses;
tempoEstimadoMinutos = Math.round((qtdLoop * 20) / 60 );
this.log = 'Tempo Estimado: ' + tempoEstimadoMinutos + ' min.' ;
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="dadosHist" ng-controller="dadosHistCtrl">
<input type="checkbox" ng-model="escolherperiodo">Escolher PerĂ­odo<br>
<div ng-if="escolherperiodo">
<input type="text" ng-model="mesini" placeholder="Mes">/<input type="text" ng-model="anoini" placeholder="Ano"><br>
<input type="text" ng-model="mesfim" placeholder="Mes">/<input type="text" ng-model="anofim" placeholder="Ano"><br>
</div>
<button ng-click="gerar()">Gerar</button> <br>
{{log}}
</div>
Always use a dot in ng-model ! . In other words use objects not primitives.
ng-if creates a child scope and since you are using primitives in ng-model you are losing 2 way binding with scope from this child scope.
var myModel ={
mesini : 1,
anoini : 2011,
mesfim : 7,
anofim : 2015
};
$scope.myModel = myModel;
HTML
<input type="text" ng-model="myModel.mesini">
Then in function:
$scope.gerar = function() {
$scope.log = myModel.anoini;
var meses = ((myModel.anofim - myModel.anoini)......
.....
}
Understanding scope nesting in angular is the most important thing to learn when using the framework
You should not assign value to this, but to $scope inside gerar function:
$scope.gerar = function() {
$scope.log = $scope.anoini;
meses = (($scope.anofim - $scope.anoini) * 12) + (12 - $scope.mesini) + $scope.mesfim;
qtdLoop = arrEstacoes.length * meses;
tempoEstimadoMinutos = Math.round((qtdLoop * 20) / 60 );
$scope.log = 'Tempo Estimado: ' + tempoEstimadoMinutos + ' min.' ;
}

angularjs move focus to next control on enter

What is the best way, when hitting enter inside a form, the focus to go to the next input instead submitting the form with angularjs.
I have a form with a lot of fields and customers are used to hit enter to move to the next input (comming from desktop applications). The angularjs saves the form when the user hits enter. I like to change this. Is it possible ?
I suggest making a custom directive. Something like this. I haven't tested this.
.directive('focus', function() {
return {
restrict: 'A',
link: function($scope,elem,attrs) {
elem.bind('keydown', function(e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
elem.next().focus();
}
});
}
}
});
Something like that should work. You might have to tweek something. Good luck.
Create a custom directive:
.directive('nextOnEnter', function () {
return {
restrict: 'A',
link: function ($scope, selem, attrs) {
selem.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
var pageElems = document.querySelectorAll('input, select, textarea'),
elem = e.srcElement || e.target,
focusNext = false,
len = pageElems.length;
for (var i = 0; i < len; i++) {
var pe = pageElems[i];
if (focusNext) {
if (pe.style.display !== 'none') {
angular.element(pe).focus();
break;
}
} else if (pe === elem) {
focusNext = true;
}
}
}
});
}
}
})
This is the directive I ended up with (thanks to Zack Argyle):
angular.module('myApp').directive("nextFocus", nextFocus);
/** Usage:
<input next-focus id="field1">
<input next-focus id="field2">
<input id="field3">
Upon pressing ENTER key the directive will switch focus to
the next field id e.g field2
The last field should not have next-focus directive to avoid
focusing on non-existing element.
Works for Web, iOS (Go button) & Android (Next button) browsers,
**/
function nextFocus() {
var directive = {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('keydown', function(e) {
var partsId = attrs.id.match(/field(\d{1})/);
var currentId = parseInt(partsId[1]);
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
document.querySelector('#field' + (currentId + 1)).focus();
}
});
}
};
return directive;
}
I tried this solution out. As advertised, it needed some tweaking. Here is what ended up working for me:
.directive("focus", function () {
return {
restrict: "A",
link: function ($scope, elem, attrs) {
var focusables = $(":focusable");
elem.bind("keydown", function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
var current = focusables.index(this);
var next = focusables.eq(current + 1).length ? focusables.eq(current + 1) : focusables.eq(0);
next.focus();
e.preventDefault();
}
});
}
}
Note that the in order to get the :focusable pseudo to work, you will need to reference JQueryUI. (the latest version 1.11.4 worked for me)
This is the directive I ended up with (thanks to Zack Argyle and Oleg):
app.directive("nextFocus", function () {
/** Usage:
<input next-focus tabindex="0" id="field1">
<input next-focus tabindex="1" id="field2">
<input id="field3">
Upon pressing ENTER key the directive will switch focus to
the next field id e.g field2
The last field should not have next-focus directive to avoid
focusing on non-existing element.
Works for Web, iOS (Go button) & Android (Next button) browsers,
**/
var directive = {
restrict: 'A',
link: function (scope, elem, attrs) {
elem.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
try {
if (attrs.tabindex != undefined) {
var currentTabIndex = attrs.tabindex;
var nextTabIndex = parseInt(attrs.tabindex) + 1;
$("[tabindex=" + nextTabIndex + "]").focus();
}
} catch (e) {
}
}
});
}
};
return directive;
});
Based on the answer by wolcy97 but using only angular
/** Usage:
<input next-focus tabindex="0">
<input next-focus tabindex="1">
<input tabindex="2">
Upon pressing ENTER key the directive will switch focus to
the next tabindex.
The last field should not have next-focus directive to avoid
focusing on non-existing element.
Works for Web, iOS (Go button) & Android (Next button) browsers,
**/
app.directive('nextFocus', [function() {
return {
restrict: 'A',
link: function(scope, elem, attrs) {
elem.bind('keydown', function(e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
try {
if (attrs.tabindex !== undefined) {
var currentTabeIndex = attrs.tabindex;
var nextTabIndex = parseInt(currentTabeIndex) + 1;
var elems = document.querySelectorAll("[tabindex]");
for (var i = 0, len = elems.length; i < len; i++) {
var el = angular.element(elems[i]);
var idx = parseInt(el.attr('tabindex'));
if (idx === nextTabIndex) {
elems[i].focus();
break;
}
}
}
} catch (e) {
console.log('Focus error: ' + e);
}
}
});
}
};
}]);
Pure JavaScript Enter as TAB
angular.module('app').directive('tabNext', function () {
return {
restrict: 'A',
link: function (scope, elem) {
elem.bind('keyup', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
var eIDX = -1;
for (var i = 0; i < this.form.elements.length; i++) {
if (elem.eq(this.form.elements[i])) {
eIDX = i;
break;
}
}
if (eIDX === -1) {
return;
}
var j = eIDX + 1;
var theform = this.form;
while (j !== eIDX) {
if (j >= theform.elements.length){
j = 0;
}
if ((theform.elements[j].type !== "hidden") && (theform.elements[j].type !== "file")
&& (theform.elements[j].name !== theform.elements[eIDX].name)
&& (! theform.elements[j].disabled)
&& (theform.elements[j].tabIndex >= 0)) {
if (theform.elements[j].type === "select-one") {
theform.elements[j].focus();
} else if (theform.elements[j].type === "button") {
theform.elements[j].focus();
} else {
theform.elements[j].focus();
theform.elements[j].select();
}
return;
break;
}
j++;
}
}
});
}
}});
<table class="table table-striped table-bordered table-hover">
<tr>
<th>S No</th>
<th>Stock Id</th>
<th>Description</th>
<th>Qty</th>
<th>UOM</th>
<th>Rate</th>
<th>Amount</th>
<th>Add</th>
<th>Delete</th>
</tr>
<tr ng-repeat="item in stockitems">
<td>{{$index + 1}}</td>
<td>
<input type="text" style="width:70px" id="stkid{{$index}}" class="form-control" name="stockid" required insert="Addnewrow();" ng-keyup="moveFocus('desc','amount','stkid','stkid',$index,$event)" ng-blur="getStockitem($index);" typeahead="a.stockitem_code as (a.stockitem_code +' | ' + a.stockitem_name +' | '+ a.rate) for a in stock | filter:$viewValue | limitTo:8" data-ng-model="item.stockid" rows="3" />
</td>
<td>
<input type="text" class="form-control" id="desc{{$index}}" name="description" ng-keyup="moveFocus('quantity','stkid','desc','desc',$index,$event)" data-ng-model="item.description" rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="quantity{{$index}}" class="form-control" ng-keyup="moveFocus('uom','desc','quantity','quantity',$index,$event)" ng-change="GetAmount($index,'qty');" ng-pattern="/^\d+$/" required name="qty" data-ng-model="item.qty" rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="uom{{$index}}" class="form-control" name="uom" ng-keyup="moveFocus('rate','quantity','uom','uom',$index,$event)" data-ng-model="item.uom" required rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="rate{{$index}}" class="form-control" name="rate" ng-keyup="moveFocus('amount','uom','rate','rate',$index,$event)" required data-ng-model="item.rate" ng-pattern="/^\d{0,9}(\.\d{1,9})?$/" ng-change="GetAmount($index,'rate');" rows="3" />
</td>
<td>
<input type="text" style="width:70px" id="amount{{$index}}" class="form-control" ng-keyup="moveFocus('stkid','rate','amount','amount',$index,$event)" name="amount" required data-ng-model="item.amount" rows="3" />
</td>
<td><span ng-click="AddEstimation($index);"><a>Add</a></span></td>
<td><span ng-click="DeleterowEstimation($index);"><a>Delete</a></span></td>
</tr>
</table>
$scope.moveFocus = function (nextId,prevId,downId,upId,index,event) {
debugger;
if (event.keyCode == 39) {
nextId = nextId + index;
$('#' + nextId).focus();
}
else if(event.keyCode == 37)
{
prevId = prevId + index;
$('#' + prevId).focus();
}
else if(event.keyCode == 38)
{
upId = upId + (index - 1);
$('#' + upId).focus();
}
else if(event.keyCode == 40)
{
downId = downId + (index + 1);
$('#' + downId).focus();
}
else if(event.keyCode==13)
{
if (nextId == "desc") {
nextId = "quantity" + index;
$('#' + nextId).focus();
}
else if(nextId == "uom")
{
nextId = "stkid" + (index + 1);
$('#' + nextId).focus();
}
}
};
On Enter press it moves to next element of DOM, but element requires id to set focus
starter.directive('focustonext', function () {
return {
restrict: 'A',
link: function ($scope, selem, attrs) {
selem.bind('keydown', function (e) {
var code = e.keyCode || e.which;
if (code === 13) {
e.preventDefault();
var pageElems = document.querySelectorAll('input, select, textarea'),
elem = e.srcElement || e.target,
focusNext = false,
len = pageElems.length;
for (var i = 0; i < len; i++) {
var pe = pageElems[i];
if (focusNext) {
if (pe.style.display !== 'none') {
document.getElementById(pe.id).focus();
break;
}
} else if (pe === elem) {
focusNext = true;
}
}
}
});
}
}
});
Thanks all..

Why Backbone Model change function inside a Marionette ItemView change event function triggers more then once?

Im working on a small project, and i have a problem with model binding. I'm using the Backbone.ModelBinder plugin for binding a model.
I'm checking changes on inputs, and get the name of the model attribute from the input data-name field. After that i check the changed data and do some stuff on the model. I have a function ChangeGuest and inside that im checking my model's (Nyiltnap.Reg) changes.
The problem is, this Nyiltnap.Reg.on("change:"+field ...){ ... } function runs as many times as many changes were made on the field named input.
Maybe i'm doing something wrong, or i missed something.
ItemView:
define(['text!templates/FormCompositeView.html', 'text!templates/EventIsFull.html', 'text!templates/ThankYou.html', 'models/RegModel'], function(Template, FullTemplate, ThankYou, Model) {
var FormCompositeView = Backbone.Marionette.ItemView.extend({
_modelBinder:undefined,
initialize: function() {
this.members = parseInt(Nyiltnap.Reg.get("members"));
this._modelBinder = new Backbone.ModelBinder();
var that = this;
Nyiltnap.Reg.on("change:name", function(r) { //HERE CHANGE TRIGGERS ONLY ONCE
if( ! _.has(r._previousAttributes, "name") ){
that.IncreaseMembers();
if(that.members < 10) that.$('.guest').attr("disabled", false);
if(that.$('#email').val() != '') that.$("#send-button").attr("disabled", false);
}
if( _.has(r._previousAttributes, "name") && r.changed.name == "" ){
that.DecreaseMembers();
Nyiltnap.Reg.unset("name");
that.$('.guest').attr("disabled", true);
that.$("#send-button").attr("disabled", true);
}
});
Nyiltnap.Reg.on("change:email", function(r) {
if( ! _.has(r._previousAttributes, "email") ){
if(that.$('#name').val() != '') that.$("#send-button").attr("disabled", false);
}
if( _.has(r._previousAttributes, "email") && r.changed.email == "" ){
that.$("#send-button").attr("disabled", true);
}
});
},
getTemplate: function() {
if( this.members < 10 ){
return _.template(Template);
}else{
return _.template(FullTemplate);
}
},
tagName: "ul",
id: "nyiltnap-form",
onRender: function() {
var MainBindings = {name : "[name=rname]", email : "#email", source : "#source", coupon : "#coupon", guest_1 : "#guest-1", guest_2 : "#guest-2", guest_3 : "#guest-3", guest_4 : "#guest-4", guest_5 : "#guest-5", guest_6 : "#guest-6", guest_7 : "#guest-7", guest_8 : "#guest-8", guest_9 : "#guest-9"};
if(this.members < 10) this._modelBinder.bind(Nyiltnap.Reg, this.el, MainBindings);
return this;
},
events: {
"change .guest" : "ChangeGuest",
"click #send-button" : "SendReg"
},
ChangeGuest: function(o) { //I WOULD LIKE TO MAKE THIS WORK
var that = this;
var field = $(o.target).data('name');
Nyiltnap.Reg.on("change:"+field, function(r) { //THIS RUNS AS MANY TIMES AS THE CONTENT OF THE 'field' HAS BEEN CHANGED
if( ! _.has(r._previousAttributes, field) ) {
that.IncreaseMembers();
that.AddInput(o);
}else{
if(_.has(r._previousAttributes, field) && _.result(r.changed, field) == ""){
that.DecreaseMembers();
}
}
});
},
IncreaseMembers: function() {
this.members++;
Nyiltnap.Reg.set("members", this.members);
Nyiltnap.vent.trigger("members:changed", this.members);
},
DecreaseMembers: function() {
this.members--;
Nyiltnap.Reg.set("members", this.members);
Nyiltnap.vent.trigger("members:changed", this.members);
},
AddInput : function(o) {
var target = $(o.target);
if(this.members < 9) target.next().next().slideDown();
}
});
return FormCompositeView;
});
Template:
<li>
<label for="guest1">My guests: </label>
<div id="guests">
<input name="guest-1" data-name="guest_1" id="guest-1" class="guest" type="text" disabled="disabled"/>
<input name="guest-2" data-name="guest_2" id="guest-2" class="guest" type="text" disabled="disabled"/>
<input name="guest-3" data-name="guest_3" id="guest-3" class="guest" style="display: none" type="text" />
<input name="guest-4" data-name="guest_4" id="guest-4" class="guest" style="display: none" type="text" />
<input name="guest-5" data-name="guest_5" id="guest-5" class="guest" style="display: none" type="text" />
<input name="guest-6" data-name="guest_6" id="guest-6" class="guest" style="display: none" type="text" />
<input name="guest-7" data-name="guest_7" id="guest-7" class="guest" style="display: none" type="text" />
<input name="guest-8" data-name="guest_8" id="guest-8" class="guest" style="display: none" type="text" />
<input name="guest-9" data-name="guest_9" id="guest-9" class="guest" style="display: none" type="text" />
<div class="clear"></div>
</div>
<div class="clear"></div>
</li>

Resources