Angular ngModel, 3 arrays are affected

Issue

I am creating a form builder in Angular, I used Lam Phuoc ThinhI work for reference, check his work here

<https://codepen.io/thinhlam/pen/BowEPp>

Now the problem is I have this 3 arrays, Current Field, Form Fields and Draggable Fields. Everytime I dragged a field, like for example the Header Field and then I changed the text or value of that field, the Draggable Fields is also affected. So if i dragged another Header field the value is the same with the first header field that i drag. Please check the image below.
image

    app.component.html
    <div *ngFor="let set of CurrentField.Settings; let i = index; trackBy:trackByIdx" [ngSwitch]="set.Type">
    <div *ngSwitchCase="'textarea'" class="form-group">
    <label for="textarea-{{i}}">{{set.Name}}</label>
    <input [name]="'textarea' + i"  type="text" class="form-control" [(ngModel)]="set.Value">
    </div>
    </div>




    app.component.ts
    FormFields: any;
    CurrentField: any;
    guid: number;
    DragElements = [{
        'Name': "Header",
        "Type": "textLabel",
        'Icon': "fa fa-header",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Header',
            'Type': 'textarea'
        }]
    }, {
        'Name': "Columns",
        "Type": "columns",
        'Icon': "fa fa-columns",
        'Settings': [{
            'Name': 'Number of Columns',
            'Value': 0,
            'PossibleValue': [2,3,4]
        }, {
            'Name': 'Column',
            'Columns': []
        }],
    }, {
        'Name': "Image",
        "Type": "image",
        'Icon': "fa fa-image",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Image',
            'Type': 'textarea'
        }]
    }, {
        'Name': "Single Text",
        'Type': "text",
        'Icon': "fa fa-font",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Single Text',
            'Type': 'text'
        }]
    }, {
        'Name': "Number",
        'Type': "number",
        'Icon': "fa fa-th-large",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Number',
            'Type': 'text'
        }]
    }, {
        'Name': "Date",
        'Type': "date",
        'Icon': "fa fa-calendar",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Date',
            'Type': 'text'
        }]
    }, {
        'Name': "Single Selection",
        "Type": "dropdown",
        'Icon': "fa fa-dot-circle-o",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Single Selection',
            'Type': 'text'
        }]
    }, {
        'Name': "Pagaraph Text",
        "Type": "textarea",
        'Icon': "fa fa-align-left",
        'Settings': [{
            'Name': 'Field Label',
            'Value': 'Paragraph Text',
            'Type': 'text'
        }]
    }];

    constructor(
        private cd: ChangeDetectorRef,
        private zone: NgZone,
    ) {}

    ngOnInit() {
        this.CurrentField = {};
        this.FormFields = [];
        this.guid = 1;
    }

    createNewField = function() {
        return {
            'id': ++this.guid,
            'Name': '',
            'Settings': [],
            'Active': true,
            'ChangeFieldSetting': function(Value, SettingName) {
                switch (SettingName) {
                    // case 'Field Label':
                    //     this.Settings[0].Value = Value;
                    //     // console.log(Value);
                    //     break;
                    case 'Image Alignment':
                        this.Settings[2].DefaultAlignment = Value;
                        break;
                    case 'Columns':
                        let columns : any = {};
                        this.Settings[0].Value = Value;
                        for(let i = 0; i < Value; i++) {
                            columns = {
                                'ID': i + "-" + this.id,
                                'Title': 'Column '+i,
                                'Items': []
                            }

                            this.Settings[1].Columns.push(columns);
                        }
                        console.log(this);
                        break;
                    default:
                        break;
                }
            },
            'GetFieldSetting': function(settingName) {
                let result = {};
                let settings = this.Settings;
                settings.forEach((index, set) => {
                    if (index.Name == settingName) {
                        result = index;
                        return;
                    }
                });

                if (!Object.keys(result).length) {
                    settings[settings.length - 1].Options.forEach((index, set) => {

                        if (index.Name == settingName) {
                            result = index;
                            return;
                        }
                    });
                }
                return result;
            }

        };
    }

    changeFieldName = function(Value) {
        this.CurrentField.Name = Value;
        this.CurrentField.Settings[0].Value = this.CurrentField.Name;
    }

    removeElement = function(idx){
        if(this.FormFields[idx].Active) {
            this.CurrentField = {};
        }
        this.FormFields.splice(idx, 1);
    };

    addElement(ele, idx) {
        // this.zone.run(() => {
            this.CurrentField.Active = false;
            this.CurrentField = this.createNewField();
            Object.assign(this.CurrentField, ele);
            if (idx == null) {
                this.FormFields.push(this.CurrentField);
            } else {
                this.FormFields.splice(idx, 0, this.CurrentField);
            }
        // });
    };

    activeField = function(f) {
        this.CurrentField.Active = false;
        this.CurrentField = f;
        f.Active = true;
    };

Solution

Wherever you are using

 Object.assign(this.CurrentField,ele);

like operations
deep clone before pushing.

Object.assign(this.CurrentField, JSON.parse(JSON.stringify(ele)));

This is one way of deep cloning which has its pros and cons. But your solution will be to deep clone using any suitable method.

Answered By – Arun Mohan

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published