Creating New Labels

In notebook:
Building Modern Web Apps
Created at:
2016-01-31
Updated:
2016-01-31
Tags:
libraries JavaScript React Ampersand
Start with an empty form.

First add a new label button.
  // ****     pages/repo-detail.js    ****
import ...

export default React.createClass({
    mixins: [ampersandMixin],
    displayName: 'RepoDetail'
    
    // ++++ 2. create the handler
    onAddClick () {
        this.props.labels.add({
            // will create the new label for us based on the model
            // just by passing some attributes
            // (or even an empty object)
            name: '',
            color: '',
            editing: true,
            // ++++ 4. set saved to false (see for this below)
            saved: false
            
        // ++++ 3. specify that we want to create it at the first position
        // just so that in the UI we see it as the first element
        }, {at: 0})
    },
    
    render () {
        const {repo} = this.props
        
        return (
            <div className='container'>
                <h1>{repo.full_name}</h1>
                <p>
                // ++++ 1. add the button
                    <button onClick={thins.onAddClick} className='button'>Add New></button> 
                </p>
                <ul>
                {labels.map( label => { ... })}
                </ul>
            </div>
        )    
    }
})
Prepare for the case when the user hits cancel after creating a new label.

Also when you want to save a new label, the PATCH will not work (cannot update a label that doesn't exist).

Ampersand model determines if has to do a PUT or POST based whether the id attribute exists or not. In our case, we use name as the id (and it's us who create the name), we need something to track if the label is new or has been saved)

We need to redefine this part of the model. Add a saved property to the model.
  // ****     label.js            ****
import ...

export default Model.extend(githubMixin, {
    idAttribute: 'name',

    props: {
        name: 'string',
        color: 'string'
    },
    
    session: {
        editing: {
            type: 'boolean',
            default: false
        },
        // ++++ 1. add the saved property
        saved: {
            type: 'boolean',
            // default to true
            default: true
        }
    },

    // ++++ 2. redefine the existing isNew property
    isNew() {
        // how we determine if the model is new or not
        // if not saved it's new
        return !this.saved
    },

    update (attributes) {
        const oldAttributes = this.attributes
        xhr({ ... }, (err, req, body) => {
            if(err) { ... }
        })
        this.set(attributes)
    }
})
We have to account for the saved state in other parts of the app
  // ****     components/label-item.js        ****
import React form 'react'
import ampersandMixin form 'ampersand-react-mixin'

export default React.createClass({
    mixins: [ampersandMixin]
    
    onDeletClick (event) { ... }
    
    onEditClick () { ... },
    
    onCancelClick () { ... },
    
    getInitialState () { ... },
    
    onNameChange (event) { ... },
    
    onColorChange (event) {...},
    
    onSubmit(event) {
        event.preventDefault()
        // ++++ 1. check if it was saves already
        if (label.saved) {
            // ++++ 2. move the update to here
            this.props.label.update(this.state)
        } else {
            // or save
            // you can pass attributes to save method
            label.save(this.state)
        }
        this.props.label.editing = false
    },
    
    render () {
        const {label} = this.props
        const {color} = this.state
        const cssColor = '#' + color
        let content
        
        if (label.editing) { 
            content = (
                <form onSubmit={this.onSubmit} className='label'>
                    ...
                    <span style={{backgroundColor: cssColor}} className="..." />
                    <input name='name' type='text' value={this.state.name} onChange={this.onNameChange} />
                    
                    <input name='color' onChange={this.onColorChange}  value={cssColor} />
                </form>
            )
        } else {
            content = (
                <div className='label'>
                    ...
                </div>    
            )
        }
        return (<div>{content}</div>)
    }
})