I'm setting a model with form, but I have a problem to set a "MyModel" with a form
This is for the purpose of optimizing the handling of the forms
public myModel = new MyModel();
this.myForm = this.formBuilder.group({
firstName: new FormControl({
value: this.myModel.firstName,
disabled: false
}),
middleName: new FormControl({
value: this.myModel.middleName,
disabled: false
}),
lastName: new FormControl({
value: this.myModel.lastName,
disabled: false
}),
age: new FormControl({
value: this.myModel.age,
disabled: false
})
});
when I submit a "submit" with a button, that shows me the "this.myForm" with the elements that I added in the form
but it seems that I would not be establishing a connection as a "TwoDataBinding"
I also do not want to do this code since I see it very redundant
also
when it comes to many forms and even worse if you decide to change or refactor the attributes of that object
this.myModel.firstName = this.myForm.controls['firstName'].value;
this.myModel.lastName = this.myForm.controls['lastName'].value;
this.myModel.middleName = this.myForm.controls['middleName'].value;
this.myModel.age = this.myForm.controls['age'].value;
You can see the complete code here:https://stackblitz.com/edit/form-model-hammer
of a form model, if you want to make changes makes a FORK to share, thanks:
also for the purpose of avoiding this alert in the picture
If you want to use 2-way binding, you should use template-driven forms instead. It allows you to use ngModel to create two-way data bindings for reading and writing input-control values.
The principles of reactive forms follows the 'one-way' rule, whereby you follow an immutable method of managing the state of your forms, such that there is greater separation of concern between your template and component logic. You can read more about the advantages of reactive forms on the above link.
If you think reactive forms is not what you want, you should revert to using template driven forms, as stated on the first paragraph.
One thing to take note, you should not use ngModel with reactive forms, as this will defeat the purpose of immutability.
However, if you are planning to stick to using reactive forms, you can simplify your code by doing this instead:
1) Initialising and declaring your reactive forms.
this.myForm = this.formBuilder.group({
firstName: [{value: this.myModel.firstName, disabled: true}],
middleName: [this.myModel.middleName],
lastName: [this.myModel.Name],
age: [this.myModel.age],
});
2) Get reactive form data:
// since the properties of myModel and myForm FormControl names are the same
this.myModel = {...this.myForm.value};
3) Update reactive form data:
this.myForm.patchValue(this.myModel);
You should stop using ngModel with Reactive forms as it is deprecated now .
You can simplify the code like below :
this.myModel.firstName= 'FIRST NAME';
this.myForm = this.formBuilder.group({
firstName:[{
value: this.myModel ? this.myModel.firstName : '',
disabled: false
}],
middleName: [{
value: this.myModel ? this.myModel.middleName : '',
disabled: false
}],
lastName: [{
value: this.myModel ? this.myModel.lastName : '',
disabled: false
}],
age:[{
value: this.myModel ? this.myModel.age : '',
disabled: false
}]
});
Listen to (ngOnSubmit) event and write a function to save the form values .
This can be achieved in the below way :
save(myForm : any){
let form = myForm as MyModel;
console.log(form);
form.otherProperties = 'nothing';
}
Or :
save(myForm : MyModel){
let form = JSON.parse(JSON.stringify(myForm)); //for copy
console.log(form);
form.otherProperties = 'nothing';
console.log( 'added a new property', form);
}
And in your html :
<div>
<form [formGroup]="myForm" (ngSubmit)='save(myForm.value)'>
<label>
<span>
Fisrt name:
</span>
<input type="text" formControlName="firstName">
</label>
<label>
<span>
Middle name
</span>
<input type="text" formControlName="middleName">
</label>
<label>
<span>
Last name
</span>
<input type="text" formControlName="lastName">
</label>
<label>
<span> Age: </span>
<input type="number" formControlName="age">
</label>
<div style="display: block">
<button (click)="onShowModel()">
show model
</button>
</div>
<div style="display: block">
<button>
set model from form
</button>
</div>
</form>
</div>
<div>
<p class="red"> from model : </p>
<span class="red"> Model: {{myModel | json}} {{nothing}}</span>
</div>
<div>
<p class="blue"> from form, binding model : </p>
<span class="blue"> Model: {{myForm.value | json}}</span>
</div>
I have also forked your example : Example
Related
I am trying to show checkboxes checked or unchecked based on certain condition. for eg:
$scope.userRoles = {"grants" : [
"Permission",
"View",
"Update",
"Delete"
]}
On the HTML part i have added the following code:
<div ng-repeat="p in userRoles">
<input type="checkbox" ng-model="p.grants.indexOf('Delete') != -1?true:false" ng-change="AddRemovePermission(p,'Delete')" />
</div>
If i use ng-checked instead of ng-model than it works fine, but i will not get 2 way binding with that. Also i know we cant use expressions like above in ng-model.
Can anybody help on how this can be done. The only condition is if user has grants than the checkbox should be checked else not, and when clicked on checkbox it should be changed to checked or unchecked accordingly and gets added in the userRoles object. Cant use directive as well.
Thanks.
The problem is your model. You must send boolean to backend, this can be a solution:
In view:
<div ng-repeat="role in userRoles.grants">
<input type="checkbox" ng-model="role.checked" />
</div>
And in controller:
$scope.userRoles = {"grants" : [
{"permission": "Permission", checked: true },
{"permission": "View", checked: false },
{"permission": "Update", checked: true },
{"permission": "Delete", checked: true }
]}
I need to add conditional Class to Form Field based on control property.
for Ex : i have in my controller
$scope.isIssueFixed = true;
and my formly object is -
$scope.formly = {
className: 'col-xs-6',
key: 'Name',
type: 'input',
templateOptions: {
label: 'Common Device Name'
}
Now how we can add a condition class to above formly field,
$scope.isIssueFixed?'ok':'No'; in formly object?
I solved the issue using Wrappers in angular formly. Here is the code which I did. May be it helps to someone.
add the bolow code to config :
formlyConfigProvider.setWrapper({
name: 'horizontalBootstrapLabel',
template: [
`<label for="{{::id}}" class="col-sm-2 control-label" >
'{{to.label}} {{to.required ? "*" : ""}}
</label>
<div class="col-sm-8" ng-class="{'bbb':model.heightlight}">
<formly-transclude></formly-transclude>
</div>`
].join(' ')
});
$scope.$watch('isIssueFixed', function() {
var classAdded = $scope.isIssueFixed ? "ok" , "No"; $scope.formly = {
className: 'col-xs-6 ' + classAdded ,
key: 'products.device[0].deviceCommonName',
type: 'input',
templateOptions: {
label: 'Common Device Name'
}
});
You can use ng-class directive of angularjs. Refere https://docs.angularjs.org/api/ng/directive/ngClass.
I have a form that has 4 fields
<form name="form">
Name:
<input type="text" ng-model="edit.name"><br />
age:
<input type="text" ng-model="edit.age"><br />
phone:
<input type="text" ng-model="edit.phone"><br />
address:
<input type="text" ng-model="edit.address"><br />
</form>
And i have an array in the app.js
$scope.statuses = [
{value: 1, text: 'status1'},
{value: 2, text: 'status2'},
{value: 3, text: 'status3'},
{value: 4, text: 'status4'}
];
I am repeating that array in the html and what i want to do is that i want the text to appear in the form when a button such as "edit" is clicked
PLUNKER
So basically as you can see in the plunker when i click on the edit button i want "status1" "status2" "status3" "status4" to appear in the fields that are in the form "name" "age" "phone" and "address"
Your question was a bit unclear, but I think what you want to do is change statuses to the form values.
I create this plunker for you
on your ng-click function. I change the statuses array text (which is shown with ng-repeat in your html) to your forms edit values:
$scope.editFunction = function(edit){
$scope.statuses[0].text=edit.name;
$scope.statuses[1].text=edit.age;
$scope.statuses[2].text=edit.phone;
$scope.statuses[3].text=edit.address;
};
or if you want your array values be in your form just reverse the = in your function like plunker :
but in this case,if you want your empty form to work, you should declare edit before in your controller.
$scope.edit=[];
$scope.editFunction = function(edit){
edit.name=$scope.statuses[0].text;
edit.age=$scope.statuses[1].text;
edit.phone=$scope.statuses[2].text;
edit.address=$scope.statuses[3].text;
};
and so you are using ng-model.there is no need to pass argument to your function, you can use $scope.edit instead of a passing argument in your editFunction
I have this quickForm:
{{> quickForm id="insertFixie" collection="Fixies" type="insert" doc=seedObject}}
Backed up by this schema:
Fixies = new Meteor.Collection('fixies');
Schema.Fixies = new SimpleSchema({
description: {
type: String,
label: "Description",
trim: true,
optional: true
},
cost: {
type: Number,
label: "Cost",
min: 0,
decimal: true
},
product_id: {
type: String,
autoform: {
omit: true
}
},
});
Fixies.attachSchema(Schema.Fixies);
and this seedObject method:
Template.insertFixie.helpers({
seedObject: function () {
console.log({product_id: this._id});
return {product_id: this._id};
}
});
When that console call directly above happens, it's correct and gives something to this effect:
Object {product_id: "1"}
But when I submit the form with something valid (like "stuff" and "100"), I get this error:
insert error:
Error: Product is required {invalidKeys: Array[1],
validationContext: SimpleSchemaValidationContext,
stack: (...),
message: "Product is required"}
stating that the product_id attribute is required and currently has a value of null.
What am I doing wrong? That product_id is a template dependent value, so something like "autoValue" in the schema doesn't seem like the best way to handle it.
The docs seem to clearly state that I'm using things correctly. From the description of the doc attribute of Auto Form:
For an insert form, you can also use this attribute to pass an object
that has default form values set (the same effect as setting a value
attribute on each field within the form).
And from the description of the value attribute of afFieldInput:
value: Set a specific, potentially reactive, value for the input. If
you have also provided a doc attribute on the autoForm or quickForm,
this value will override the value from the doc object.
What am I missing?
Edit
I added an autoValue field to my schema, just to see what pops up:
autoValue: function (doc) {
console.log(doc)
console.log(this.value)
return "1";
}
This allows the form to correctly submit, but with the incorrect hard-coded value of "1" rather than a useful value from the template. The two console logs show this:
:24 Object {description: "stuff", cost: 50}
:25 undefined
It seems my seedObject value isn't available to autoValue.
Do I have to hijack the onSubmit hooks? Do I have to have hidden form inputs with values supplied from the template? What's the fix here?
It turned out to be a hidden input.
I expanded my form to this:
{{#autoForm id="insertFixie" collection="Fixies" type="insert"}}
<fieldset>
{{> afFormGroup name="description" placeholder="schemaLabel" label=false}}
<div class="form-group{{#if afFieldIsInvalid name='cost'}} has-error{{/if}}">
<div class="input-group">
<div class="input-group-addon">$</div>
{{> afFieldInput name="cost" placeholder="schemaLabel" label=false}}
</div>
{{#if afFieldIsInvalid name="cost"}}
<span class="help-block">{{afFieldMessage name="cost"}}</span>
{{/if}}
</div>
{{> afFormGroup name="product_id" type="hidden" value=_id}}
</fieldset>
<button class="btn btn-primary" type="submit">Insert</button>
{{/autoForm}}
Adding an afFormGroup with type="hidden" did exactly the trick.
Although it still seems to me like the doc argument isn't living up to it's promises.
I need to be able to dynamically create parameter objects in Angular which have the following form:
[
password: {type: 'String', required: true, value: 'apassword'},
someRandomParam: {type: 'Integer', required: false, value:3}
]
I know how to bind to this in order to display the values in a list or table, but I don't know how to construct this object with bindings in Angular, primarily in creating the key ("password") as these keys are created dynamically too.
I'm assuming that you meant having an object, not an array (your code will generate SyntaxError), like that:
$scope.params = {
password: {type: 'String', required: true, value: 'apassword'},
someRandomParam: {type: 'Integer', required: false, value:3}
};
It's true that you can bind to it, even using ngRepeat. But adding something to that object needs something more than just a simple bind. Create some inputs in your view:
<input type="text" ng-model="newParamName" />
<input type="text" ng-model="newParam.type" />
<input type="checkbox" ng-model="newParam.required" />
<input type="text" ng-model="newParam.value" />
<input type="button" ng-click="addParam(newParamName, newParam)" value="Add me!" />
...and in controller:
$scope.addParam = function(name,param){
$scope.params[name] = angular.copy(param);
};