jeudi 20 avril 2017

Angular 4 detecting real form changes

I'm working on some Angular (4 + Typescript) application with custom architecture and I'm building base component for forms. However I want to create this component as much generic as possible, so I can reuse it for every form I'm building in my app. So the only problem I have after I pulled everything together is with class and approach for changes the user do in form. To explain how it currently works ...

I have one property for model which is based on some class (Animal, Car, ...) and it's empty (only initialized without props) when user is adding new instance of it, or has properties set to whatever it needs when user is editing existing instance. There is also another property for changes which is of Object type and it should only contain changed values from original model. I'm detecting changes of form fields with merged subscription of every field's valueChanges and I update values accordingly in second property with changes. In method where I check for changes I've implemented to remove "class property" from changes Object in case it's same as previous or it contains same elements in case of array. The reason why I decided for such approach is because I want to track changes immediately and just send it when user submit form - I could also do diff on submit, but in case of large form I think this could be a problem. The original model must be retained in case that user perform revert of fields. So the thing that is annoying me with this implementation is, that I need two separate properties for practically the same model, where one is original and in other are only changes.

My idea is to create something like proxy class where I would store original model (passed via component input) and I'd also keep changes in it. When model would be used somewhere it should only return changed properties, original properties would be fetched from method like getOriginal() or something. In case of direct property call, it should return either the original value or changed value if exists. I created pseudo class for my idea, since I don't know all the TypeScript/JavaScript patterns which would help me to achieve this - I also looked at Proxy pattern from ES6, but I couldn't create what I described before with it ...

class FormModel {

    protected changedModel: Object; 

    constructor(protected originalModel: any) {}

    get(propName: string): any {
        if (this.originalModel.hasProperty(propName) && this.changedModel.hasProperty(propName)) {
            // if has property defined in class but not set
            return this.originalModel[propName] || this.changedModel[propName];
        }

        throw Exception(`Property '${propName}' doesn't exist.`);
    }

    set(propName: string, value: any): void {
        if (this.originalModel[propName] !== value) { // also there should array comparison
            this.changedModel[propName] = value;
        }
    }

    getChanged(): any {
        return this.changedModel;
    }

    getOriginal(): any {
        return this.originalModel;
    }

}

Example class animal used in example below:

class Animal {
    constructor(
        public name: string,
        public age: number,
        protected sound: string
    ) {}
}

So example for usage of this would be:

let animal = new Animal('Johnny', 4, 'Abcdefgh');
let model = new FormModel(animal);

console.log(animal);
console.log(model);
console.log(model.name);

model['name'] = 'Ynnhoj';

console.log(model); // same as if I'd call model.getChanged()
console.log(model.getOriginal());

And output of it:

Animal { name: 'Johnny', age: 4, sound: 'Abcdefgh' }
Object {}
'Johnny'
Object { name: 'Ynnhoj', age: 4, sound: 'Abcdefgh' }
Animal { name: 'Johnny', age: 4, sound: 'Abcdefgh' }

So that's basically what I would like to achieve if it's possible. I believe this is not possible at all, so I will really appreciate any suggestion on how to implement actual form changes (not if I change text field from "value" to "value1" and from "value1" back to "value" right after the first change, to treat this as a change of property). Thank you in advance!






Comments
0 Comments

0 commentaires:

Enregistrer un commentaire