Sending Updated to Github, part 1

In notebook:
Building Modern Web Apps
Created at:
2016-01-30
Updated:
2016-01-31
Tags:
libraries JavaScript React Ampersand backend
Looks up github API.
​PATCH /repos/:owner/:repo/labels/:name​ 
PATCH : partial update to a given thing (normally you could just send the name but not the color . For the label Github requires to send both name and color)

Normally when you save a model, ampersand-rest-model will do a PUT. We have to change this to PATCH. 
The name is in the url. If we change the name, our model will use the wrong URL (because it uses the new name)
On the label we will do an update method. It will do a custom request instead of reconfigure the model default behaviour.
  // ****     label.js            ****
import Model from 'ampersand-model'
import githubMixin from '../helpers/github-mixin'
// ++++ 2. import the xhr library
import xhr from 'xhr'

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

    props: {
        name: 'string',
        color: 'string'
    },
    
    session: {
        editing: {
            type: 'boolean',
            default: false
        }
    },
    
    // ++++ 1. create an update method
    update (attributes) {
        xhr({
            url: ,
            json: attributes,
            method: 'PATCH',
            headers: {
                Authorization: 'token ' + app.me.token
        })
    }
})
Talks about DRY and refactoring (he's repeating himself with the headers definition

He would in this case create a small npm repo that wraps the headers and use that

He recommends to get in the habit of refactoring "as you go". Don't be afraid to refactor often and wherever you see fit.

Or the audience asks if you could do the headers in the github mixin. But then it adds methods that is not coherent with the name (githubMixin)
Continues with the update method. Error handling.
  // ****     label.js            ****
import ...

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

    props: {
        name: 'string',
        color: 'string'
    },
    
    session: { ... },

    update (attributes) {
        // ++++ 1. save the old attributes
        const oldAttributes = this.attributes
        // this.attributes follows the Backbone convention
        xhr({
            // ++++ 3. build the url
            url: this.url(), // here we can still use "old" url
            // it was not updated yet, we will set it after 
            // we sent the request
            json: attributes,
            method: 'PATCH',
            headers: {
                Authorization: 'token ' + app.me.token
        // ++++ 2. define a method for error handling
        }, (err, req, body) => {
            if(err) {
                this.set(oldAttributes)
                console.err('something went wrong...')
            }
        })
        // ++++ 4. save the attribute
        // (optimistic update, we set it right after we fired the xhr request)
        // (if it fails it will revert)
        // you can apply multiple properties with .set method
        this.set(attributes)
    }
})

Handling the submitting of the form

  // ****     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) {...})
    }
    
    // ++++ 2. onsubmit handler
    onSubmit(event) {
        // ++++ 3. stop the browser sending the GET
        event.preventDefault()
        this.props.label.update(this.state)
        // (we're already keeping track of the state)
        // ++++ 4. set the form back to view mode
        this.props.label.editing = false
        // (we could have pulled out the label)
        // (with const {label} = this.props)
    }
    
    render () {
        const {label} = this.props
        const {color} = this.state
        const cssColor = '#' + color
        let content
        
        if (label.editing) { 
            content = (
                // ++++ 1. add the form submit handler
                <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>)
    }
})  
Advises to use the ​form​ element, even though you could do it with a ​div​ because you can submit it with a enter key. Doesn't break what the user expects.