Last active
April 26, 2018 04:32
-
-
Save andybluntish/4e0b9fb429484901a61cf0c732e9a28d to your computer and use it in GitHub Desktop.
Bulk Save
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import DS from 'ember-data' | |
const { JSONAPIAdapter } = DS | |
export default JSONAPIAdapter.extend({ | |
namespace: 'api', | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
const { Controller } = Ember | |
export default Controller.extend({ | |
appName: 'Manage Students', | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
const { | |
A, | |
get, | |
isArray, | |
isPresent, | |
} = Ember | |
export function includes([obj, item]) { | |
if (isArray(obj)) { | |
return A(obj).includes(item) | |
} | |
return isPresent(get(obj, item)) | |
} | |
export default Ember.Helper.helper(includes) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
const { | |
A, | |
Controller, | |
computed, | |
computed: { readOnly }, | |
get, | |
} = Ember | |
export default Controller.extend({ | |
teacher: readOnly('model.teacher'), | |
students: computed('model.students.@each', { | |
get() { | |
return A(get(this, 'model.students')).sortBy('id') | |
}, | |
}).readOnly(), | |
teacherSchoolClasses: computed('teacher.schoolClasses.[]', { | |
get() { | |
return A(get(this, 'model.schoolClasses')).sortBy('id') | |
}, | |
}).readOnly(), | |
schoolClasses: computed('model.schoolClasses.[]', { | |
get() { | |
return A(get(this, 'model.schoolClasses')).sortBy('id') | |
}, | |
}).readOnly(), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
const { | |
Route, | |
RSVP: { hash }, | |
get, | |
} = Ember | |
export default Route.extend({ | |
model() { | |
const store = get(this, 'store') | |
return hash({ | |
teacher: store.findRecord('teacher', 1), | |
students: store.findAll('student'), | |
schoolClasses: store.findAll('schoolClass'), | |
}) | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function() { | |
this.namespace = 'api' | |
this.get('/teachers') | |
this.get('/teachers/:id') | |
this.get('/students') | |
this.put('/students', (schema, req) => { | |
const { data } = JSON.parse(req.requestBody) | |
console.log(JSON.stringify(data, null, 2)) | |
const updated = data.map((item) => { | |
const record = schema.students.find(item.id) | |
record.update(item.attributes) | |
return record | |
}) | |
return updated | |
}) | |
this.get('/students/:id') | |
this.patch('/students/:id') | |
this.get('/school-classes') | |
this.get('/school-classes/:id') | |
this.patch('/school-classes/:id') | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Factory } from 'ember-cli-mirage' | |
export default Factory.extend({ | |
name(i) { return `Class ${i + 1}` }, | |
afterCreate(schoolClass, server) { | |
server.createList('student', 5, { schoolClasses: [schoolClass] }) | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Factory, faker } from 'ember-cli-mirage' | |
export default Factory.extend({ | |
firstName() { return faker.name.firstName() }, | |
lastName() { return faker.name.lastName() }, | |
grade() { | |
return faker.random.number({ | |
min: 1, | |
max: 5, | |
}) | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Factory, faker } from 'ember-cli-mirage' | |
export default Factory.extend({ | |
firstName() { return faker.name.firstName() }, | |
lastName() { return faker.name.lastName() }, | |
afterCreate(teacher, server) { | |
server.createList('schoolClass', 2, { teachers: [teacher] }) | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Model, hasMany } from 'ember-cli-mirage' | |
export default Model.extend({ | |
teachers: hasMany('teacher'), | |
students: hasMany('student'), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Model, hasMany } from 'ember-cli-mirage' | |
export default Model.extend({ | |
schoolClasses: hasMany('schoolClass'), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Model, hasMany } from 'ember-cli-mirage' | |
export default Model.extend({ | |
schoolClasses: hasMany('schoolClass'), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default function(server) { | |
server.create('teacher') | |
server.createList('student', 20) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { JSONAPISerializer } from 'ember-cli-mirage' | |
export default JSONAPISerializer.extend() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ApplicationSerializer from './application' | |
export default ApplicationSerializer.extend({ | |
include: ['teachers', 'students'], | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ApplicationSerializer from './application' | |
export default ApplicationSerializer.extend({ | |
include: ['schoolClasses'], | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import ApplicationSerializer from './application' | |
export default ApplicationSerializer.extend({ | |
include: ['schoolClasses'], | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import DS from 'ember-data' | |
const { | |
Model, | |
attr, | |
hasMany, | |
} = DS | |
export default Model.extend({ | |
name: attr('string'), | |
teachers: hasMany('teacher', { async: true }), | |
students: hasMany('student', { async: true }), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
import DS from 'ember-data' | |
const { | |
computed, | |
get, | |
} = Ember | |
const { | |
Model, | |
attr, | |
hasMany, | |
} = DS | |
export default Model.extend({ | |
firstName: attr('string'), | |
lastName: attr('string'), | |
grade: attr('number'), | |
schoolClasses: hasMany('school-class', { async: true }), | |
fullName: computed('firstName', 'lastName', { | |
get() { | |
return [ | |
get(this, 'firstName'), | |
get(this, 'lastName'), | |
].join(' ').trim() | |
}, | |
}), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
import DS from 'ember-data' | |
const { | |
computed, | |
get, | |
} = Ember | |
const { | |
Model, | |
attr, | |
hasMany, | |
} = DS | |
export default Model.extend({ | |
firstName: attr('string'), | |
lastName: attr('string'), | |
schoolClasses: hasMany('school-class', { async: true }), | |
fullName: computed('firstName', 'lastName', { | |
get() { | |
return [ | |
get(this, 'firstName'), | |
get(this, 'lastName'), | |
].join(' ').trim() | |
}, | |
}), | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
const { | |
A, | |
Component, | |
RSVP: { all }, | |
computed, | |
computed: { readOnly, oneWay }, | |
get, | |
isEqual, | |
set, | |
} = Ember | |
export default Component.extend({ | |
selectedRecords: A(), | |
teacher: null, | |
schoolClass: null, | |
students: computed('schoolClass.students.[]', { | |
get() { | |
return A(get(this, 'schoolClass.students')).sortBy('id') | |
}, | |
}).readOnly(), | |
studentCount: readOnly('students.length'), | |
gradeOptions: A([1, 2, 3, 4, 5]), | |
updateGradeTo: oneWay('gradeOptions.firstObject'), | |
noRecordsSelected: computed('selectedRecords.[]', { | |
get() { | |
return get(this, 'selectedRecords.length') < 1 | |
}, | |
}), | |
allRecordsSelected: computed('students.[]', 'selectedRecords.[]', { | |
get() { | |
return isEqual(get(this, 'students.length'), get(this, 'selectedRecords.length')) | |
}, | |
}).readOnly(), | |
actions: { | |
toggleAllSelected(isChecked) { | |
if (isChecked) { | |
set(this, 'selectedRecords', A(get(this, 'students').toArray())) | |
} else { | |
set(this, 'selectedRecords', A()) | |
} | |
}, | |
selectRecord(student, isChecked) { | |
if (!student) return | |
if (isChecked) { | |
get(this, 'selectedRecords').addObject(student) | |
} else { | |
get(this, 'selectedRecords').removeObject(student) | |
} | |
}, | |
// Remove a single Student from a single SchoolClass - 1 request | |
// - remove the SchoolClass from the Student model | |
// - save the Student model, sending its complete new data without the removed SchoolClass | |
removeFromClass(student) { | |
get(student, 'schoolClasses').removeObject(get(this, 'schoolClass')) | |
student.save() | |
get(this, 'selectedRecords').removeObject(student) | |
}, | |
// Remove multiple Students from a single SchoolClass - 1 request | |
// - remove the SchoolClass from each selected Student model | |
// - save the SchoolClass model, sending its complete new data without the removed Students | |
removeSelectedFromClass() { | |
get(this, 'selectedRecords').forEach((student) => { | |
get(student, 'schoolClasses').removeObject(get(this, 'schoolClass')) | |
}) | |
get(this, 'schoolClass').save() | |
get(this, 'selectedRecords').clear() | |
}, | |
// Remove multiple Students from multiple (all) SchoolClasses - 1 request per affected SchoolClass | |
// - track a list of every SchoolClass the selected Students belong to | |
// - remove all SchoolClass relationships from each selected Student | |
// - save each of the affected SchoolClass models, sending their complete new data without the removed Students | |
removeSelectedFromAllClasses() { | |
const schoolClasses = A() | |
get(this, 'selectedRecords').forEach((student) => { | |
schoolClasses.pushObjects(get(student, 'schoolClasses').toArray()) | |
get(student, 'schoolClasses').clear() | |
}) | |
schoolClasses.uniq().forEach((schoolClass) => schoolClass.save()) | |
get(this, 'selectedRecords').clear() | |
}, | |
moveSelectedIntoGrade() { | |
const newGrade = get(this, 'updateGradeTo') | |
if (!newGrade) return | |
const savePromises = [] | |
get(this, 'selectedRecords').forEach((student) => { | |
if (get(student, 'grade') !== newGrade) { | |
set(student, 'grade', newGrade) | |
savePromises.push(student.save({ adapterOptions: { bulkSave: true } })) | |
} | |
}) | |
all(savePromises).then((students) => { | |
console.log('Saved selected students:', A(students).mapBy('fullName').join(', ')) | |
}) | |
}, | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
const { | |
Component, | |
get, | |
computed, | |
} = Ember | |
export default Component.extend({ | |
tagName: 'tr', | |
student: null, | |
schoolClasses: null, | |
studentSchoolClasses: computed('student.schoolClasses.[]', { | |
get() { | |
return get(this, 'student.schoolClasses').mapBy('id') | |
}, | |
}), | |
actions: { | |
addStudentTo(schoolClass) { | |
const student = get(this, 'student') | |
get(student, 'schoolClasses').pushObject(schoolClass) | |
student.save() | |
}, | |
}, | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember' | |
import ApplicationAdapter from '../application/adapter' | |
const { | |
A, | |
RSVP: { Promise }, | |
get, | |
run, | |
set, | |
} = Ember | |
export default ApplicationAdapter.extend({ | |
_bulkUpdatesQueue: null, | |
_bulkUpdatesResolvers: null, | |
_bulkUpdates(type) { | |
// Bulk updates make a PUT request to the collection endpoint (e.g. /api/students) | |
const url = this.urlForFindAll(type) | |
const method = 'PUT' | |
const options = { | |
data: { | |
data: get(this, '_bulkUpdatesQueue'), | |
}, | |
} | |
set(this, '_bulkUpdatesQueue', A()) | |
this.ajax(url, method, options) | |
.then(() => get(this, '_bulkUpdatesResolvers').forEach((p) => p.resolve())) | |
.catch(() => get(this, '_bulkUpdatesResolvers').forEach((p) => p.reject())) | |
.finally(() => set(this, '_bulkUpdatesResolvers', A())) | |
}, | |
init() { | |
set(this, '_bulkUpdatesQueue', A()) | |
set(this, '_bulkUpdatesResolvers', A()) | |
}, | |
updateRecord(store, type, snapshot) { | |
// Bulk save functionality is triggered by an adapter option passed to model.save() | |
// Do the normal thing if we're not bulk saving... | |
if (!get(snapshot, 'adapterOptions.bulkSave')) return this._super(...arguments) | |
// Build an object with changed properties only | |
const record = { | |
attributes: {}, | |
id: snapshot.id, | |
type: type.modelName, | |
} | |
const changedAttributes = snapshot.changedAttributes() | |
Object.keys(changedAttributes).forEach((key) => { | |
// changed attributes are returned from the snapshop as an array [oldValue, newValue] | |
record.attributes[key] = changedAttributes[key][1] | |
}) | |
// Add the record to the queue | |
get(this, '_bulkUpdatesQueue').pushObject(record) | |
// Trigger the updates on the queue (debounced) | |
run.debounce(this, get(this, '_bulkUpdates'), type.modelName, 50) | |
return new Promise((resolve, reject) => { | |
get(this, '_bulkUpdatesResolvers').pushObject({ resolve, reject }) | |
}) | |
} | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
html { box-sizing: border-box; } | |
*, *:before, *:after { box-sizing: inherit; } | |
body { | |
color: #333; | |
font-family: sans-serif; | |
} | |
.row { | |
display: grid; | |
grid-template-columns: repeat(2, 1fr); | |
grid-column-gap: 1em; | |
} | |
table { | |
border-collapse: collapse; | |
} | |
th, td { | |
padding: 0.75em 0.5em; | |
text-align: left; | |
border-bottom: 1px solid #eee; | |
} | |
tr:hover td { | |
background: #f4fbff; | |
} | |
td label { | |
display: block; | |
padding: 0.75em 0.5em; | |
margin: -0.75em -0.5em; | |
} | |
[disabled] { | |
opacity: 0.6; | |
} | |
button { | |
font-size: inherit; | |
padding: 0.5em 0.8em; | |
background: transparent; | |
border: 1px solid #eee; | |
border-radius: 3px; | |
line-height: 1; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "0.13.1", | |
"ENV": { | |
"ember-cli-mirage": { | |
"enabled": true | |
} | |
}, | |
"EmberENV": { | |
"FEATURES": {} | |
}, | |
"options": { | |
"use_pods": true, | |
"enable-testing": false | |
}, | |
"dependencies": { | |
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js", | |
"ember": "2.12.0", | |
"ember-template-compiler": "2.12.0", | |
"ember-testing": "2.12.0" | |
}, | |
"addons": { | |
"ember-data": "2.12.2", | |
"ember-cli-mirage": "0.3.2" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment