Realm-js: provide example of using classes for realm objects with custom methods

Created on 31 Aug 2017  Â·  6Comments  Â·  Source: realm/realm-js

Goals

I have a class defined like so:

export class Task {
  static schema = {
    name: 'Task',
    primaryKey: 'id',
    properties: {
      id: { type: 'string', indexed: true },
      title: { type: 'string' }
    }
  }
  constructor (title) {
    this.title = title || ''
    this.id = Utils.guid()
  }
  static getTasks = () => {
    return realm.objects('Task')
  }
  setTitle = title => {
    realm.write(() => {
      this.title = title
    })
  }
}
...
export default new Realm({
  schema: [Task],
})

I can do Task.getTasks(), but if I call task.setTitle('Changed Title!') on one of the Task objects from realm, I get an error that setTitle is not defined. this way of defining classes is mentioned in #141, so I would assume it would be possible still.

I've tried a few different ways to get this working, including defining the Task schema separately from the Task class, and extending Realm.Object, but can't find a method that works. A documented solution would be ideal for this.

Most helpful comment

okay final update for some reason it's working in different files, perhaps that wasn't the problem. but here's the code I needed. perhaps an example like this could be added to the docs?
file: Task.js

import realm from './realm'
export class Task {
  static schema = {
    name: 'Task',
    primaryKey: 'id',
    properties: {
      id: { type: 'string', indexed: true },
      title: { type: 'string' }
    }
  }

  static getTasks () {
    return realm.objects('Task')
  }
  static newTask (title) {
    realm.write(() =>
      realm.create('Task', { title: 'test', id: Math.random().toString() })
    )
  }
  setTitle (title) {
    realm.write(() => {
      this.title = title
    })
  }
}

file: realm.js

import { Task } from './task'
const realm = new Realm({
  schema: [
    Task
  ],
})

export default realm

file: TasksView.js

export default class Tasks extends Component {
  constructor (props) {
    super(props)
    this.state = { tasks: Task.getTasks() }
    this.create = this.create.bind(this)
  }
  componentDidMount () {
    const tasks = Task.getTasks()
    tasks.addListener(() => this.setState({ tasks: Task.getTasks() }))
  }
  create () {
    Task.newTask('test')
  }
  render () {
    return (
      <ScrollView>
        {Array.from(this.state.tasks).map(task => (
          <Button
            onPress={() => task.setTitle('changed title!')}
            title={task.title}
            key={task.id}
          />
        ))}
        <Button onPress={this.create} title={'new'} />
      </ScrollView>
    )
  }
}

All 6 comments

What happens if you use the method syntax to define the methods like

static getTasks() {
    return realm.objects(‘Task’);
}

setTitle(title) {
    realm.write(() => this.title = title);
}

?

@fealebenpae I'm getting an error that only says 'ObjectSchema'. I think realm is not finding the static schema property on my Task class?
edit:
I can define the schema as a separate object (i.e. TaskSchema ={...}) and pass that to realm, but I end up with the same problem that setTitle() is undefined, even using the method syntax.
but doing this:

class Task {
  static schema = {...}
  constructor () {...}
  setTitle () {...}
} 
...
export default new Realm({schema:[Task]})

does not work. (gives objectSchema error)

Is this a React Native project? Can you prepare a small repro for us to debug?

@fealebenpae I'll get to work on it. But I should be able to pass a class with a schema static member to realm without an issue right?

@fealebenpae figured it out. I had export default new Realm({schema:[Task]}) in one file, and Task class declaration in another. in the Task file I was importing the realm instance from the first file, and I think something about the two files requiring each other was causing the error. unfortunately I now don't know how I can split these statements up, but that's a separate problem I guess... 🤔

okay final update for some reason it's working in different files, perhaps that wasn't the problem. but here's the code I needed. perhaps an example like this could be added to the docs?
file: Task.js

import realm from './realm'
export class Task {
  static schema = {
    name: 'Task',
    primaryKey: 'id',
    properties: {
      id: { type: 'string', indexed: true },
      title: { type: 'string' }
    }
  }

  static getTasks () {
    return realm.objects('Task')
  }
  static newTask (title) {
    realm.write(() =>
      realm.create('Task', { title: 'test', id: Math.random().toString() })
    )
  }
  setTitle (title) {
    realm.write(() => {
      this.title = title
    })
  }
}

file: realm.js

import { Task } from './task'
const realm = new Realm({
  schema: [
    Task
  ],
})

export default realm

file: TasksView.js

export default class Tasks extends Component {
  constructor (props) {
    super(props)
    this.state = { tasks: Task.getTasks() }
    this.create = this.create.bind(this)
  }
  componentDidMount () {
    const tasks = Task.getTasks()
    tasks.addListener(() => this.setState({ tasks: Task.getTasks() }))
  }
  create () {
    Task.newTask('test')
  }
  render () {
    return (
      <ScrollView>
        {Array.from(this.state.tasks).map(task => (
          <Button
            onPress={() => task.setTitle('changed title!')}
            title={task.title}
            key={task.id}
          />
        ))}
        <Button onPress={this.create} title={'new'} />
      </ScrollView>
    )
  }
}

Was this page helpful?
0 / 5 - 0 ratings