When upgrading to Angular 4, I am getting the following warning in the console:
it looks like you're using the disabled attribute with a reactive form
directive. If you set disabled to true when you set up this control in
your component class, the disabled attribute will actually be set in
the DOM for you. We recommend using this approach to avoid 'changed
after checked' errors.ֿ
When doing something like this:
<input type="text" formControlName="name" [disabled]="isDisabled">
it's seems that Angular does not like anymore when we use the disabled property on form control.
What is changed and why it's happening?
It means that you are setting the disabled property through property binding, but you are using formControl which gives reactive nature.
So, you should be declaring the {disable: true} in the code as below,
form = new FormGroup({
name: new FormControl({value: '', disabled: true})
});
Note: If you are using reactive forms you should be having a formGroup attribute defined in your HTML.
LIVE DEMO
Related
I was trying to setvalue to my form and would like to disable the form.
Somehow if I setvalue to form it is working fine but as soon I write disable method my ng-select value is going out.
Have anyone faced same issue while disabling the ng-select with values?
form = new FormGroup({
code: new FormControl()
});
values = [{
value: "0"
label: "test1"
},
{
value: "1"
label: "test2"
}
]
//I am setting values using setvalue and disbling after wards
this.form.controls['code'].setValue('0')
this.form.disable();
<ng-select formControlName="code" [items]="values" bindValue="value" labelForId="code"
[clearable]="false" [selectOnTab]="true" placeholder="Select one" data-e2e-id="code">
</ng-select>
Are you sure that you change value?
Method to set value:
Methods using setValue()
this.form.get("code").setValue('0');
this.form.controls["code"].setValue('0');
Methods using patchValue()
this.form.get("code").patchValue('0');
this.form.controls['code'].patchValue('0');
this.form.patchValue({"code": '0'});
In you case could be the problem that form updates only after applying disablibg and you doesn`t see that you update filed on a wrong way
You can disable/enable a form control when you initialize it by setting disabled to true as follows
users.push(this.fb.group({
userType: this.fb.control({value: 'Admin', disabled: true})
}));
You can do so by calling the disable/enable methods for that particular form control to perform it dynamically.
// To enable form control
userType.enable();
// To disable form control
userType.disable();
I have an Angular Reactive form. I subscribe to its value changes and will emit changes to parent component. Some of the controls might get disabled by the user. The problem is that values from disabled controls are missing when form valueChanges are emitted. I've set a basic example.
When the checkbox is checked and the email input is disabled, there is no form control value logged. But I'd like to get ALL form values.
Use the FormGroup's getRawValue() to include control values regardless of enable/disable state.
More information in the API documentation
this.myForm.valueChanges.subscribe(() => {
this.formValues = JSON.stringify(this.myForm.getRawValue());
});
Here is the forked example
The value from a disable input is ignored (try to submit a form with a disabled input: it won't be posted).
You can change it to 'readonly'
<input formControlName="email" [readonly]="cb.checked">
<input #cb type="checkbox" formControlName="toggleEmail">
Updated example.
this.form.valueChanges
.pipe(map((_) => this.form.getRawValue()))
.subscribe(res => {
console.log(res)
});
I am struggling to figure out a way to trigger these AngularJS classes on a form I am trying to automatically fill with a chrome extension I am making. The form (specifically a textbox) has to be validated/modified before it will be validated and therefore submitted.
I originally tried using javascript to set the value of the textbox using the value property. This did not validate the form. I then tried using a dispatch event to send a key to the textbox, which resulted in nothing being input into the text box. How can I validate the form without requiring human input, or is this not possible?
Clarification, I am trying to replicate this action without user input by using a chrome extension.
Reference https://www.w3schools.com/angular/angular_validation.asp
Sounds like you need to create some events to simulate whatever angular is listening for, probably change or blur. Here's an example using click from mozilla:
https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events#Triggering_built-in_events
function simulateClick() {
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {
// A handler called preventDefault.
alert("cancelled");
} else {
// None of the handlers called preventDefault.
alert("not cancelled");
}
}
How can I validate the form without requiring human input
Get the forms controls:
var controls = $scope.tdForm.$getControls();
Trigger their validators:
controls.forEach( _ => _.$validate() );
From the Docs:
$validate();
Runs each of the registered validators (first synchronous validators and then asynchronous validators). If the validity changes to invalid, the model will be set to undefined, unless ngModelOptions.allowInvalid is true. If the validity changes to valid, it will set the model to the last available valid $modelValue, i.e. either the last parsed value or the last value set from the scope.
For more information, see
AngularJS Form Controller API Reference
AngularJS ngModelController API Reference
When you type into the form, it updates the state of its controls (touched, dirty, etc.). According to how you define your fields validators (required, minLength...) the form will be valid or not after the user input.
In your submit method you should not proceed if any form fields are not valid. See AngularJS Developer Guide — Forms or Scotch Tutorials — AngularJS Form Validation you can have more details about AngularJS validation.
As Mike mentioned, you can use ngClass conditionally (see below) to apply some style classes only if a boolean condition occurr, for example the form is not valid.
<div ng-controller="ExampleController">
<form name="form" novalidate class="css-form">
<input type="text" ng-model="user.name" name="username" ng-class="{ 'error': !isValid }"/>
<div ng-show="form.$submitted>
<span ng-show="form.username.$error">Wrong Name</span></span>
</div>
<button ng-click="submit(user)"> Submit </button>
</form>
</div>
angular.module('formExample', [])
.controller('ExampleController', ['$scope', function($scope) {
$scope.isValid = true;
$scope.submit= function(user) {
if (user.name != 'Carl') {
$scope.isValid = false;
}
};
}]);
You can always programmatically change the form states if needed. For example to set the field to pristine:
$scope.form.$setPristine();
$scope.form.$setUntouched();
$setPristine sets the form's $pristine state to true, the $dirty state to false, removes the ng-dirty class and adds the ng-pristine class.
Additionally, it sets the $submitted state to false. This method will also propagate to all the controls contained in this form.
$setUntouched sets the form to its untouched state. This method can be called to remove the 'ng-touched' class and set the form controls to their untouched state (ng-untouched class).
Setting a form controls back to their untouched state is often useful when setting the form back to its pristine state.
UPDATE
Now it is clear what you are attempting to achieve. The two methods above can be used to set the form state, but if you want to validate it from code (this can be done passing the form to a service or directly in the controller for instance) then $validate() method will allow you to achieve that as mentioned by George.
I have a cascading dropdown using VueJS (1.0), and I'm having a problem where a change in the Vue model isn't being reflected in the DOM.
The elements in the dropdown need to be an object, but once selected I'm trying to change the value of the property/dropdown to an int.
I'm doing this with a watch event, which processes the necessary information from the object, then uses $set on the property to set it to the required int.
Using the VueJS Chrome dev tools, I can see the change reflected on the component's property, but when submitting the form it's POSTed as the string [object Object], as if the DOM was never updated.
Here is the relevant dropdown in the template:
<select :disabled="releases.length < 1" v-model="release" options="releases" class="form-control input-sm" name="{{formname}}[release_id]">
<option selected="selected" value="">Choose Release...</option>
<option v-for="obj in releases" v-bind:value="obj">{{obj.text}}</option>
</select>
And here is the watch event:
"release": function() {
this.$parent.$data.promos = this.release.promos;
this.$set('release', this.release.id);
}
After changing the dropdown, the root promos property is updated, and according to dev tools the release property of the component is correctly set to the id
But when the form is submitted, I just get the string representation of the object!
Does anyone know what I'm doing wrong here; or is this a VueJS bug/is there a workaround?
Thank you!
I will not be able to find the bug in your code unless I can play around with it in jsFiddle or equivalent.
But I have an alternate implementation of cascading dropdown for you here: https://jsfiddle.net/mani04/Lgxrcc5p/1/
You may see if that provides any pointers. This example uses Vue 2.0.3
In your code sample above, I specifically do not understand this part:
<select :disabled="releases.length < 1" ...
Is that a copy-paste error? I hope you have the following code in your editor:
<select :disabled="releases.length < 1" ...
The value attribute of an option can be tied to an object in Vue, but the browser still needs to render the value as valid HTML so the object is cast to a string.
One thing you can do is add a hidden field to the form with a value set to the ID of the selected release object.
Edit: Another option could be overriding the toString method of the class prototype to return the ID of the object.
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".