Facing problem with "can.Model.findAll( params[, success[, error]] )"

I am learning basics of CanJs through one of the video tutorial “Getting Started with CanJS” by Justin Meyer.

Below is the content of todos.js:


var Todo = can.Model({
findAll: ‘GET /todos’,
findOne: ‘GET /todos/{id}’,
create: ‘POST /todos’,
update: ‘PUT /todos/{id}’,
destroy: ‘DELETE /todos/{id}’
}, {});

(function () {

TODOS = [{ "id": 57, "name": "Ice Water" }, { "id": 58, "name": "Toast" }];

can.fixture({ type: 'GET', url: '/todos' }, function () {
    return TODOS;
});

can.fixture({ type: 'GET', url: '/todos/{id}' }, function (request) {
    return TODOS[(+request.data.id)-1];
}); 

})();


Now after opening chrome console when i type in the below command:

Todo.findAll({},function(todo){console.log(todo[0].attr(‘name’))},function(xhr){console.log(xhr)})

Below is the output i get:

Object {}

Object {readyState: 4, responseText: “[object Object],[object Object]”, status: 200, statusText: “success”}

The problem i am facing is console.log(todo[0].attr(‘name’)) doesnot display the content accordingly.

You are best off storing your fixtures in a separate isomorphic repo, and then essentially creating a fixture generator within that repo as a bin that overrides to JSON files, which are what’s actually passed around to your fontend & backend.

Create your set algebra in model, and then require it into your fixtures to keep things DRY.

// #assets/models/fixtures/todo

var todos = require('@acme/fixtures').todos,
  algebra = require('../todo').algebra,
  fixture = require('can-fixture');

var store = fixture.store(todos, algebra);

fixture({
  'GET /todos': store.findAll,
  'GET /todos/{_id}': store.findOne,
  'POST /todos': store.create,
  'PUT /todos/{_id}': store.update,
  'DELETE /todos/{_id}': store.destroy
});

module.exports = store;

Switch over to using can-connect/can/super-map/ from can.Model. It’s a lot more feature rich, and doing so will let you take advantage of the newer fixture functionality. Otherwise, it reverts to legacy mode.

// #assets/models/todo

var superMap = require('can-connect/can/super-map/'),
  tag = require('can-connect/can/tag/'),
  config = require('config'),
  set = require('can-set'),
  can = require('can');

var algebra = new set.Algebra(
  set.comparators.id('_id')
);

require('can/map/define/');


var Todo = can.Map.extend({}, {
  define: {
    __v: {
      value: 0,
      type: 'number',
      serialize: false
    }
  }
});

Todo.List = can.List.extend({
  Map: Todo
}, {});

var connection = superMap({
  url: {
    resource: config.hosts.api + '/todos'
  },
  idProp: '_id',
  Map: Todo,
  algebra: algebra,
  List: Todo.List,
  name: 'todo'
});

tag('todo-model', connection);

exports.Todo = Todo;
exports.algebra = algebra;
exports.connection = connection;
exports.store = connection.instanceStore;

Pro tip #1: Make a “config” module that maps to JSON files for the respect environment. This should be essentially identical to the config module conventions. This one doesn’t really make sense as an isomorphic config just because the server side config will almost assurdely have sensitive information.

"system": {
  "directories": {
    "lib": "assets"
  },
  "envs": {
    "development": {
      "map": {
        "config": "./assets/config/development.json"
      }
    },
    "production": {
      "map": {
        "config": "./assets/config/production.json"
      }
    },
    "staging": {
      "map": {
        "config": "./assets/config/staging.json"
      }
    }
  },
  "npmAlgorithm": "flat",
  "map": {
    "config": "./assets/config/development.json"
  }
},

Pro tip #2: lists can be replaces from promises or constructed from promises.

These all work:

var todos = new Todo.List({}); // implicit findAll
var todos = new Todo.List([]);

todos.replace(Todo.findAll({}));
var todos = new Todo.List(Todo.findAll({}));

This is really helpful because you’ll find it’s easier & more performant to split up behavior accross multiple props.

Pro tip #3: Split up your behavior

todos: {
  value: Array,
  Type: Todo.List,
  get: function( list ) {
    var promise = this.attr('promise');

    if (promise) {
      list.replace(promise);
    }

    return list
  }
},
params: {
 // I like using this.serialize within a getter. This approach requires debouncing / batching usually
 // You can also inline replace properties on a map to make your resultant value idempotent.
 value: Object,
 get: function( map ) {
  map.attr(this.serialize(), true);
  return map;
 }
},
promise: {
 // Convert params into AJAX request
}

Good luck!