Angular 14 reactive form how to reset formarray inside formgroup - angular-reactive-forms

I am using Angular 14 and reactive forms. I have a form with a formarray inside formgroup.
On reset, i want to reset the form and formarray with initial state. I tried
this.conditionalActionForm.reset();
this.conditionalActions.clear();
but getting the error There is no FormControl instance attached to form control element with path: 'conditionalActions -> 0 -> whenValue'
get conditionalActions(): FormArray {
return this.conditionalActionForm.get('conditionalActions') as FormArray;
}
this.conditionalActionForm = this.formBuilder.group({
conditionalActions: this.formBuilder.array(this.getConditionsArray())
});
private getConditionsArray(): FormGroup[] | null {
return [
this.formBuilder.group(
{
whenValue: [''],
comment: [false],
attachment: [false],
actionPlan: [false]
},
{
validators: [this.checkConditionalValidation]
})
];
}
How to clear the form and formarray and bring back to initial state.

Try resetting using clear
this.conditionalActions.clear()

Related

change local data object on change of global state

I am trying to edit and update using vuex. I have two components, one is form for entry/edit and another for viewing data. When I click on edit button of view component I want to populate the form component with the data from backend.
Note that I already have a data object on form component that is bind with form and used to store data. I want to change it on edit. I have no problem on getting data from backend.
I just can not change the local data object from state
This is my codes what I've tried
Form component:
import { mapState } from 'vuex'
export default {
data(){
return{
form:{
id:'',
name:'',
email:'',
phone:'',
address:''
}
}
},
computed:{
...mapState({
data (state) {
this.form=state.employee; //This is where I am stuck
}
}),
}
state:
export default{
state:{
employee:{}
},
getters:{}
},
mutations:{
setEmployee(state,employee){
state.employee=employee;
}
},
actions:{
fetchEmployee({commit},id){
axios.put('employee-edit/'+id)
.then(res=>res.data)
.then(employee=>{
commit('setEmployee',employee)
})
}
}
}
view component:
export default {
methods:{
editEmployee(id){
this.$store.dispatch('fetchEmployee',id);
}
}
}
Multiple issues/misunderstandings with your approach.
1) computed properties are "passive" and supposed to return a value "computed" from other values. Directly assigning to your local state is probably not what you want to do.
2) HTTP methods: In general the HTTP PUT method replaces the resource at the current URL with the resource contained within the request.
Please read up on http methods and how they are supposed to be used. You want GET
3) mapState is a helper method if you need multiple getters from vuex state store. I suggest you use this.$store.getters.myVariableInState for simple tasks like in your example.
What you probably want is more along these lines:
// store
getters:{
employee: state => state.employee
}
// component
computed: {
employee() {
return this.$store.getters.employee
}
}
If your actions was already dispatched earlier and the data is available in the store all you then need is
methods: {
editEmployee() {
this.form = this.employee
}
}
Since your question stated "change local data on state change", here is an approach for that:
watch your local computed property
watch: {
employee() {
// this.employee (the computed value) now refers to the new data
// and this method is triggered whenever state.employee changes
}
}

aframe state component - pass data from state to component

I am making use of aframe-state-component to build a game and tracking the game level and play/pause status through the state variables.
I am looking to understand how to pass state data to a component with properties.
Here is my state -
AFRAME.registerState({
initialState: {
score: 0
},
handlers: {
gamePaused: function(state) {
state.gamePaused = true;
},
gameStarted: function(state, event) {
state.gamePaused = false;
state.level = event.source;
}
}
});
and I pass the level to gameStarted handler by emitting an event in my angular controller -
el.emit('gameStarted', {source: levelnumber}, true);
and here is my html
<a-entity bind__model-subset="target: #orca; gamelevel: level"></a-entity>
the component "model-subset" originally accepted only "target" property. I included gamelevel property in there so that I can pass the state variable level to this component. Thereafter I modified, the model-subset component to include the gamelevel property in the schema as shown below -
AFRAME.registerComponent('model-subset', {
schema: {
target: { default: '', type: 'selector' },
gamelevel: { type: 'number'}
},
init: function() {
var data = this.data;
var el = this.el;
console.log("model-subset level is ", data.gamelevel); //this component does not get executed
}
})
But, it errors out and the component code does not get executed. Could you please give me an example of how to pass state data to different components that already have a few properties in their schema?
good question.
In a bind__ component, you only pass state properties, not any real values. Real values go in the component defininition itself. So move target: #orca out into model-subset since that's just a value.
<a-entity bind__model-subset="gamelevel: level" model-subset="target: #orca"></a-entity>

Reactive Form SetValue for FormGroup Array inside observable subscribe method

I am new the Angular but I am trying to understand How can we use Reactive Form and FormGroups array while we use the Service Observable.
My form is very simple, It has list of Articles, where you can select one of them and can edit the detail. It also has feature to add new article.
So, starting of the page itself, It has list of articles in left side and reactive blank form on other side.
Now, this form also contain some of the checkbox which provides the tags for an article.
Now, when I load the page, everything is coming as expected. Articles are coming and reactive form is also loading along with all the tags (un-checked)
When I click any of the article to make that editable, I am getting an error
"Must supply a value for form control at index: 0."
I tried to change the code little but but with that the new error started coming
"Must supply a value for form control with name: 'articleId'"
So, overall I am not getting what is fundamental issue. Seems like I am missing to give a name to the formgroup but not sure how to supply.
// Global Variables: Called from the constructor.
articleDetailForm: FormGroup;
tagFormArray: FormArray = new FormArray([]);
// While this.loadArticle(this.selectedArticleId); called on change event
private loadArticle(selectedArticleID: string) {
this.articleService.getArticle(selectedArticleID)
.subscribe(
(data: ArticleViewModel) => {
const _a = new ArticleViewModel(data);
debugger;
this.articleDetailForm.setValue({
articleBasicDetail: this.setBasicDetailForSelectedArticle(_a),
articleTagDetail: this.setTagDetailForSelectedArticle(_a.ArticleTagViewModels)
})
},
(err) => {
console.log(err);
});
}
private setBasicDetailForSelectedArticle(articleVM: ArticleViewModel) {
return new FormGroup({
articleId: new FormControl(articleVM.articleTitle, ),
articleTitle: new FormControl(articleVM.articleTitle),
articleContent: new FormControl(articleVM.articleContent)
});
}
private setTagDetailForSelectedArticle(articleTagsVM: ArticleTagViewModel[]) {
// want to loop through variable and checked only those tags which are available for this article
return new FormGroup({
tagId: new FormControl(111),
tagName: new FormControl("111"),
isChecked: new FormControl(true)
});
}
private createArticleDetailForm() {
let articleId = 'Dummy ID';
let articleTitle = 'Dummy Title';
let articleContent = 'Dummy Content';
this.articleDetailForm = this.formBuilder.group({
articleBasicDetail: this.formBuilder.group({
articleId: [{ value: articleId, disabled: true }, Validators.required],
articleTitle: [articleTitle, Validators.required],
articleContent: [articleContent, Validators.required],
}),
articleTagDetail: this.tagFormArray
});
}
ERROR Error: Must supply a value for form control with name: 'articleId'.
ERROR Error: "Must supply a value for form control at index: 0."

redux-form: enableReinitialize is not working

In my form I am passing the initialvalues through the below code. The initialvalues are being set. The initialization works only one time. after that the initialization values are not changing
const mapStateToProps1 = (state) => {
return {
initialValues : getValues(state.ingredients.formcomb.form.data)
}
}
const mapDispatchToProps1 = (dispatch) => {
return {
fetchData: (url) => dispatch(itemsFetchData(url)),
};
};
IngredientForm = connect( mapStateToProps1,mapDispatchToProps1 )(
reduxForm(
{
form: 'ingredient',
enableReinitialize: true,
//validate,
}
)(IngredientForm)
);
Even if i do enableReinitialize: true,, the values are not initialized if the form is submitted successfully.
Because when the form is submitted successfully it returns back the same initialvalues as previous. So there is no change in the state. If there is no change in the sate then the INITIALIZE action will not be called.
The only way to reinitialize a successfully submitted form is to use this.props.reset() if there are no form errors are returned.
I found the answer here:
How can I clear my form after my submission succeeds?

Is it possible to change props value from method in Vue component?

I have a component and i am passing value 543 to props :prop-room-selected,
<navigation-form :prop-room-selected='543'>
</navigation-form>
Now, From a button click, i am calling the function updateCoachStatus to change the value of propRoomSelected, but the props value is not updating.
{
template: '#navigation-form',
props: ['propRoomSelected'],
data: function () {
return {
roomSelected: this.propRoomSelected,
}
},
methods:{
updateCoachStatus: function(event){
this.propRoomSelected = 67;
}
}
}
I dont know how to change the value of props from function. Is it possible in Vue to update the value of props??
What you are doing will throw a warning in Vue (in the console).
[Vue warn]: Avoid mutating a prop directly since the value will be
overwritten whenever the parent component re-renders. Instead, use a
data or computed property based on the prop's value. Prop being
mutated: "propRoomSelected"
The value will actually change inside the component, but not outside the component. The value of a parent property cannot be changed inside a component, and, in fact, the updated value will be lost if the parent re-renders for any reason.
To update the parent property, what you should do is $emit the updated value and listen for the change in the parent.
Vue.component("navigation-form",{
template: '#navigation-form',
props: ['propRoomSelected'],
data: function () {
return {
roomSelected: this.propRoomSelected,
}
},
methods:{
updateCoachStatus: function(event){
this.$emit("update-room-selected", 67) ;
}
}
})
And in your parent template listen for the event
<navigation-form :prop-room-selected='propRoomSelected'
#update-room-selected="onUpdatePropRoomSelected">
</navigation-form>
Here is an example.
This is a common pattern and Vue implemented a directive to make it slightly easier called v-model. Here is a component that supports v-model that will do the same thing.
Vue.component("navigation-form-two",{
template: '#navigation-form-two',
props: ['value'],
data: function () {
return {
roomSelected: this.value,
}
},
methods:{
updateCoachStatus: function(event){
this.$emit("input", 67) ;
}
}
})
And in the parent template
<navigation-form-two v-model="secondRoomSelected">
</navigation-form-two>
Essentially, for your component to support v-model you should accept a value property and $emit the input event. The example linked above also shows that working.
Another approach is using a computed property for handling props:
{
template: '#navigation-form',
props: ['propRoomSelected'],
data () {
return {
roomSelected: this.computedRoomSelected,
changeableRoomSelected: undefined
}
},
computed: {
computedRoomSelected () {
if (this.changeableRoomSelected !== undefined) {
return this.changeableRoomSelected
}
return this.propRoomSelected
}
},
methods: {
updateCoachStatus (event) {
this.changeableRoomSelected = 67
}
}
}

Resources