In Backbone is there a bind a model attribute to an input field so that when the input value changes the model attribute will be automatically set to the current value?
At the moment I have the following in my view
<input type="text" name="firstname" class="form-input" value="<%- model.firstname %>" />
Then in the view I listen to the following event and set the model attribute accordingly
events: {
"keydown .form-input": "setAttribute"
},
setAttribute: function() {
//Use model.set on the attribute that was changed
}
To me this seems like a bad way of doing it. Am I missing an easier way of doing it?
That's the right way to do it with vanilla Backbone. If you would like to set up automated data binding you'll need a plugin like Epoxy.
Using Epoxy, your example would look something like:
var BindingView = Backbone.Epoxy.View.extend({
bindings: {
"[name=firstname]": "value:firstName",
}
});
This binds the model's firstName attribute to the input with name="firstname".
Related
I have several similar fields in my form:
<select class="form-control" name="Ops[1][WorkCentre]">..</select>
<select class="form-control" name="Ops[2][WorkCentre]">..</select>
...
<select class="form-control" name="Ops[n][WorkCentre]">..</select>
I don't know how many such fields there will be, as the user adds the fields dynamically.
I need some way of executing a java script function when any of these inputs changes, and inside that function I need to be able to access the key of the input which has changed with regards to the 'Ops' array.
Im happy to use jquery. I was thinking something like
$('select[name=Ops[i][WorkCentre]').change(function(i){
// A function using i
});
Or maybe a Javascript event listener?
Any help is appreciated.
You can use event delegation:
// Listen for 'change' event on every element that has class 'form-control'
$(document).on('change', 'select.form-control', function() {
var name = $(this).attr('name');
// You code here ...
});
UPDATE
In order to extract the number from name attribute, you can set the name as follows:
name="Ops_[1]_[WorkCentre]"
and then split by '_':
var number = $(this).attr('name').split('_')[1];
UPADATE #2
A better solution would be to set the number in a separate attribute like this:
<select class="form-control" name="Ops[1][WorkCentre]" data-number="1">..</select>
and then retrieve it like this:
var number = $(this).attr('data-number');
Here is the scenario I'm currently in:
I have three HTML elements. A textbox called shipToAddress, another textbox called deliverToAddress and a checkbox called sameAsShipToAddress.
I then have a kendo view model behind the scenes that contains a variable called address which will hold a string of an address ex: "123 Main Street".
When the page first loads, the shipToAddress element data-binds to the kendo view model's address variable ex: "123 Main Street". The deliverToAddress has no data-bind what so ever when the page initially loads. However once the sameAsShipToAddress checked box gets checked, I want to add a data-bind attribute to the deliverToAddress so it too will look at the kendo view model's address variable.
Here is the HTML:
<input id="shipToAddress"
data-bind="value: address" />
<input type="checkbox"
id="deliverSameAsShipTo"
value="deliverSameAsShipTo"
data-bind="checked: sameAsShipToAddress,
events: { click: differentDeliveryAddress }" />
<input id="deliverToAddress" />
And here is the backend Kendo View Model:
var _vm = kendo.observable({
address: "",
sameAsShipToAddress: false,
differentDeliveryAddress() {
if (!this.sameAsShipToAddress)
$("#deliverToAddress").attr("data-bind", "value: address");
else
$("#deliverToAddress").removeAttr("data-bind");
}
});
Can this be done? I feel like I'm close with the following code but currently the deliverToAddress' value property is not getting set. Do I need to some how refresh the deliverToAddress element's attributes?
Your code works correctly and you are very close to the final solution. Instead of setting the value of the bound field, set the "binding definition" as the property value:
$("#deliverToAddress").attr("data-bind", "value: address");
The ViewModel is already bidirectionally bound, so rebind the model and the binding will work in both directions.
After adding the property (and thus binding to the address field of the ViewModel) you need to set also the value of the deliverToAddress field. After that the binding resp. unbinding (set the value to empty string here) works correctly - you can see using the browser DOM explorer, that the attribute is added - change the address text and click the test button - deliverToAddress changes too.
I have created an example in the Telerik Dojo.
The view model code looks like this (I have added a button to test the behaviour):
$(document).ready(function(){
var vm = kendo.observable({
address: "",
sameAsShipToAddress: false
});
kendo.bind(document.body, vm);
//
$("#setDeliverAddressButton").kendoButton({
click: function(e) {
console.log(vm.sameAsShipToAddress);
if (vm.sameAsShipToAddress) {
$("#deliverToAddress").attr("data-bind", "value: address");
$("#deliverToAddress").val(vm.address);
}
else {
$("#deliverToAddress").removeAttr("data-bind");
$("#deliverToAddress").val("");
}
}
});
$("#triggerChangeButton").kendoButton({
click: function(e) {
kendo.bind(document.body, vm);
}
});
});
The HTML:
<input id="shipToAddress" data-bind="value: address" />
<input type="checkbox"
id="deliverSameAsShipTo"
value="deliverSameAsShipTo"
data-bind="checked: sameAsShipToAddress" />
<input id="deliverToAddress" />
<button role="button" id="setDeliverAddressButton">set deliver address</button>
bidirectional update
Another option (or even you need to do this always) is to trigger the change programatically as described in this discussion: How to update the ViewModel after programatic changes.
I am not sure whether its logical to get.
Here is the html code for my input box.
<input type="text" id="name" #name="ngForm" [ngFormControl]="userProfileForm.controls['name']"
[(ngModel)]="loggedUserInfo.name" (change)="firechange($event,'name')"
/>
and here is my firechange function
firechange($event, field){
if(this.userProfileForm.controls[field].valid){
this._userService.updateUserProfile(this.loggedUserInfo);
this._userService.loadUserData();
}
}
I want to pass only the event in the firechange function and inside the fire change function I want to get the input field name from the event so that I can understand that which input field in my form triggered the event. Expected code will be something like that
[ngFormControl]="userProfileForm.controls['name']"
[(ngModel)]="loggedUserInfo.name" (change)="firechange($event)"
/>
firechange($event){
if(this.userProfileForm.controls[$event.fieldname].valid){
this._userService.updateUserProfile(this.loggedUserInfo);
this._userService.loadUserData();
}
}
My ideal requirement is, in a form there are number of form fields, I don't even want to write firechange function in each individual form field. Is there any generic way to call the event on each input field value change for a particular form without writing it on each input field?
To get the actual name of the element you can do the following:
firechange(event){
var name = event.target.attributes.getNamedItem('ng-reflect-name').value;
console.log('name')
}
If the id is the same as the name you are passing you can get the name like
firechange(event){
if(this.userProfileForm.controls[$event.target.id].valid){
}
If you want to get hold of the element from within your fire change function you may want to try something like:
firechange(event){
let theElement = event.target;
// now theElement holds the html element which you can query for name, value and so on
}
If you in addition you want to instruct your component to apply the firechange() logic on all of your input fields with one single instruction in your component (and not having to specify this on every single input field) than I suggest you to look at in Angular2 how to know when ANY form input field lost focus.
I hope this helps
If id is not the same or it can change, here's more leverage...
You may want to reflect the [name] property the the element's attribute:
... #input [name]="item.name" [attr.name]="item.name" (change)="fn(input)" ...
Then,
...
fn(input) {
log(input.name); // now it returns the name
}
...
See more here
Try this:
<input type="text" (change)="firechange($event.target.value)">
This worked for me in Angular 10
$event.source.name
I am new to Angular JS. When the user check/uncheck on a check box, I am calling a function in a controller using ng-click. I am passing $event to the function in controller. Using the $event, I am able to get the srcElement inside the controller function. Now I would like to set the previous check/uncheck value to the check box based on certain conditions.
$scope.isAccessChanged = function(event){
if (some condition) {
var elem = angular.element(event.srcElement);
/** here how to set the elem value back to whatever it was before.*/
}
};
Lets say you have check box like
<input ng-model="form.isSelected" type="checkbox">
All you need to do is:
$scope.form.isSelected = !$scope.form.isSelected;
Avoid DOM manipulation and limit jQuery use as much as possible in angular.
I recommend using jQuery only in directives to make it less of an available option.
Try this out:
<input type="checkbox" ng-model="foShizzle" ng-click="isAccessChanged()"/>
$scope.isAccessChanged = function(event){
if(some condition){
$scope.foShizzle = !$scope.foShizzle; // This will reverse the user's decision
}
}
In my view model I update an observable's property. The property is bind to an input element.
After I change the value (from JS), the view updates.
The thing is I have other elements on the page that subscribes the the input's change event, which doesn't publish when the value is updated.
Update (Code):
Model:
var viewModel = {
email: ko.observable()
}
Html:
<input class="form-input" data-bind="value: email" type="email" />
JS: (as a result of some click):
$('.form-input').change(function () {
// doesn't happen
});
viewModel.email('someemail#aaa.com');
Instead of using change, use the Knockout subscribe function. Observables Documentation
viewModel.email.subscribe(function(newValue) {
// Called whenever the value is updated
doSomethingWithNewValue(newValue);
});