Ember Store Issue

i tried to solve these problem but failed , can anyone please help me to out from these issues!! my app -

When i use to click these two button (“Delete” and “Mark as Done”) back to back then these problem are occurred. my errors - When i clicked “Mark as Done” Button

WARNING: The 'id' for a RecordIdentifier should not be updated once it has been set. Attempted to set id for 'tasks:101 (@ember-data:lid-tasks-101)' to 'null'.

Then when i click “Delete” Button- Error: Attempted to handle event loadingData on <tasks:102> while in state root.deleted.inFlight.

When i click another time on “Delete” button or “Mark as Done” button -

Error: Assertion Failed: Attempted to schedule a fetch for a record without an id.

these type of errors occurs again and again . please help me.

app/adapters/tasks.js


import RESTAdapter from '@ember-data/adapter/rest';

export default class TasksAdapter extends RESTAdapter {
  host = 'http://localhost:3000';
}

app/serializers/tasks.js

import JSONSerializer from '@ember-data/serializer/json';

export default class TasksSerializer extends JSONSerializer {}

app/models/tasks.js

import Model, { attr } from '@ember-data/model';
export default class TasksModel extends Model {
  @attr('string') title;
  @attr('string') priyority;
  @attr('date') createdAt;
  @attr('boolean') isCompleted;
  @attr('boolean') isDeleted;
}

app/controllers/index.js

import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';
export default class IndexController extends Controller {
  @service store;
  @tracked formState = false;
  @action
  toggleForm() {
    this.formState = !this.formState;
  }
  get totalTasks() {
    return this.model.length;
  }

  deleteTask = async (taskId) => {
    try {
      console.log(taskId);
      // const task = await this.store.peekRecord('tasks', taskId);
      // await task.deleteRecord();
      // task.save();
      const task = await this.store.findRecord('tasks', taskId, {
        reload: true,
      });
      task.destroyRecord();
    } catch (error) {
      console.log(error);
    }
  };

  markAsDone = async (taskId) => {
    try {
      console.log(taskId);
      const task = await this.store.findRecord('tasks', taskId, {
        reload: true,
      });
      task.isCompleted = true;
      task.save();
    } catch (error) {
      console.log(error);
    }
  };

  get totalCompleted() {}

  get totalDeleted() {}
}

app/routes/index.js

import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class IndexRoute extends Route {
  @service store;
  async model() {
    return await this.store.findAll('tasks', { reload: true });
  }
}

app/templates/index.hbs

<Main @formState={{this.formState}} @toggleForm={{this.toggleForm}}>
    <TaskDashboard @totalTasks = {{this.totalTasks}} />
    
</Main>
<div class="container app-max-width">
    <div class="row">
        {{#if (eq this.model.length 0)}}
            <div class="empty-image">
                <img src="assets/images/empty-task.jpg" alt="Empty Tasks. Create One">
            </div>
            <h6 class="text-center">Empty ! Create New One</h6>
        {{else}}
            {{#each @model as |task|}}
                <Task @task-name={{task.title}} @task-tag={{task.priyority}} @created-at={{task.createdAt}} @deleteTask={{this.deleteTask}} @markAsDone={{this.markAsDone}} @taskId={{task.id}} />   
            {{/each}}  
        {{/if}}
    </div>
</div>

app/components/task.hbs

<div class="row">
    <div class="col">
        <div>
            <h4>{{@task-name}}</h4>
            <h6> {{@task-tag}} </h6>
            <h6> {{@created-at}} </h6>
        </div>
    </div>
    <div class="col">
        <div>
            <button class="delete-button btn btn-danger" type="button" {{on 'click' (fn @deleteTask @taskId)}}>Delete Task</button>
            <button class="mark-button btn btn-info" type="button" {{on 'click' (fn @markAsDone @taskId)}}>Mask as Done</button>
        </div>
    </div>
</div>

Can anyone please help me ?

Does the “mark as done” operation send a PUT/PATCH request correclty? And assuming the answer is yes, what is the response payload from the server?

ok, i tried again and again but unable to solve :smile:

Here is the response payload - After Clicking “Mark as Done”

{
	"title": "No Title",
	"priyority": "NORMAL",
	"createdAt": "2022-09-29T03:32:17.000Z",
	"isCompleted": true,
	"isDeleted": false
}

Ah ok so Ember Data expects that response to have the full record data (including the id) but the server isn’t providing the id in the response, so Ember Data is throwing that error because essentially it’s going to overwrite the id that is there to null. Ideally your server should send the id in this payload.

3 Likes

Thanks a lot @dknutsen … your solution works perfectly.

But when i click delete button it says another Error Like this , (in FireFox Browser)

Even Data delete on server but still exist on ember data . and next delete operations are not working for this error…

And in Chrome Browser the Error Look like this-

i tried a lot but not able to solve .

can you please help me ?

Hmmm those stack traces aren’t super revealing :thinking:

What does the DELETE request/response look like? It’s possible it’s a similar thing where Ember Data expects one thing and your server does something different so the server deletes the record but the client chokes on the reponse.

2 Likes

DELETE Response From Server is -

and my delete operation in controller is -

app/controllers/index.js

 @action
  deleteTask(taskId) {
    let task = this.store.peekRecord('tasks', taskId);
    task.deleteRecord();
    task.save();
  }

ok… i’m not 100% sure if this is the issue but i think Ember Data expects either:

  • a 200 response with an empty object in the body { }
  • OR at 204 response with no body

Giving it a 200 with a string payload might be confusing it, so that would be my first guess is to try one of the above instead.

2 Likes