ghidoz / angular2-jsonapi

A lightweight Angular 2 adapter for JSON API
199 stars 123 forks source link

hasDirtyAttributes: true right after findAll #167

Closed michDostal closed 6 years ago

michDostal commented 6 years ago

Hello I have problem with loading data, right after I load them from backend, entity has hasDirtyAttributes:true and on save its sending complete entity back to backend instead of only changed fields. happens for findAll() and find()

screenshot_7 list.component.ts

ngOnInit() {
this.clients = this.route.snapshot.data['clients'].getModels();
}

client.resolve.ts

export class ClientsResolve implements Resolve<any> {
  constructor(private datastore: ClientDatastore) {
  }

  resolve(route: ActivatedRouteSnapshot): Observable<any> | Promise<any> | any {

    let include = '';
    if (route.data.include) {
      include += route.data.include;
    }
    return this.datastore.findAll(Client, {
      include: include
    });
  }
}

client.routes.ts

{
    path: 'list',
    component: ClientListComponent,
    data: {
      breadcrumb: 'Přehled',
      include: 'advisor'
    },
    resolve: {
      clients: ClientsResolve
    }
  },

client.datastore.ts

const config: DatastoreConfig = {
  baseUrl: environment.apiURL + '/v2',
  models: {
    client: Client,
    advisors: Advisor,
    goals: Goal
  }
};

@Injectable()
@JsonApiDatastoreConfig(config)
export class ClientDatastore extends JsonApiDatastore {
  constructor(http: Http) {
    super(http);
    this.headers = new Headers({'Authorization': 'Bearer ' + localStorage.getItem('token')});
  }
}
michDostal commented 6 years ago

@abrararshad after some research I found that this problem is caused by this commit(https://github.com/ghidoz/angular2-jsonapi/commit/bb1bfdf2c40ee26f530839c2e227519b91019611) where is absolutely ignored if its new instance created from query or not

Birdr518 commented 6 years ago

I can confirm this issue. Using Version 4.1.0 all attributes of my data objects are considered as "dirtyAttributes" - even right after loading them from the backend.


 this.dataStore.findRecord(ApiUsers, "", {}, this.authenticationHeader, 
      ApiStringsService.baseUri + "/my/profile"
    ).subscribe((apiUser: ApiUsers) => {

      console.log(apiUser.hasDirtyAttributes);  // -> true
      apiUser.email = "bla";
      console.log(apiUser.hasDirtyAttributes);` // -> true

});

Using Version 4.0.0 this issue is gone and the first console.log will output false.

But still, if i have an attribute in the form like this:

 @Attribute()
  person:
    {
      title: string,
      firstname: string,
      lastname: string,
      fullname: string,
      gender: number,
      birthday: {
        date: Date,
        timezone_type: number,
        timezone: string
      }
    };

changing one nested attribute like person.title not only person.title isn't considered as a "dirty attribute", nor its parent person (the whole attribute) is stated as "dirty attribute". Is this behaviour intended?

michDostal commented 6 years ago

@Birdr518 I am currently working on fix and also feature to work better with therse nested attributes. I hope i will be able to create pull request in next week.

RicardoNeves commented 6 years ago

@house-md any updates on this?

RicardoNeves commented 6 years ago

@house-md, is there any place where we can see those changes?

MarkCorneth commented 6 years ago

Currently I fixed it by overriding the entity constructor and manually setting the oldValue and the hasDirtyAttributes property.

constructor(_datastore: JsonApiDatastore, data?: any) {
        super(_datastore, data);
        for (let key in this[AttributeMetadata]) {
            if (this[AttributeMetadata].hasOwnProperty(key)) {
                this[AttributeMetadata][key]['oldValue'] = this[AttributeMetadata][key]['newValue'];
                this[AttributeMetadata][key]['hasDirtyAttributes'] = false;
            }
        }
    }

This way the save function only includes the actually dirty attributes in the PATCH

@house-md do you have any updates on your fix?

michDostal commented 6 years ago

Hello @RicardoNeves and @MarkCorneth. I am sorry for my late reply. In branch #167-hasDirtyAttributes is my actual implementation. There is a little bit reworked dirty checking and working with old/newValue.

I also added nested array/object attributes. I am currently testing this solution for nested attributes. I am not happy with it but after maybe 10 different aproaches but this one seems working.

I tried mupltiple solutions with Proxy array/objects but in the end it always had some kind of bug or ended up with infinite loops of getters and apply methods (I still have code to this solution so I will try to finish it but for now this one should be also working. There is one setback -> for nested attributes I had to put their dirtyChecking to method in model -> hasDirtyAttributes which is always called before save and can be triggered by user any time.