Forked from theoldcounty/components.checkbox-component.js
Last active
October 2, 2018 13:28
-
-
Save NullVoxPopuli/468a737efbbf447966dd83ac734f62ad to your computer and use it in GitHub Desktop.
Parent / Child Component Communication
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 Component from '@ember/component'; | |
import { action, computed } from '@ember-decorators/object'; | |
import { check } from 'twiddle/utils/tree-helpers'; | |
export default class extends Component { | |
options = [{ | |
id: 1, | |
label: 'burger', | |
checked: false, | |
children: [{ | |
id: 3, | |
label: 'tomato', | |
checked: false | |
}, { | |
id: 4, | |
label: 'lettus', | |
checked: false | |
}, { | |
id: 5, | |
label: 'pickle', | |
checked: false | |
}] | |
}, { | |
id: 2, | |
label: 'kebab', | |
checked: false, | |
children: [{ | |
id: 6, | |
label: 'ketchup', | |
checked: false | |
}, { | |
id: 7, | |
label: 'chilli', | |
checked: false | |
}] | |
}, { | |
id: 8, | |
label: 'coffee maker', | |
checked: false, | |
children: [{ | |
id: 9, | |
label: 'filter', | |
checked: false | |
}, { | |
id: 10, | |
label: 'grounds', | |
checked: false | |
}] | |
}]; | |
@action | |
toggleChecked(id) { | |
const newTree = check(this.options, id); | |
this.set('options', newTree); | |
} | |
} |
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'; | |
export default Ember.Controller.extend({ | |
appName: 'Ember Twiddle', | |
items : [{ | |
"title" : "burger", | |
"id": "bk2", | |
"subgroup" : [ | |
{"name" : "tomato", "id": "tomo2"}, {"name" : "lettuce", "id": "let2"}, {"name" : "pickle", "id": "pickl3"}] | |
}, | |
{ | |
"title" : "kebab", | |
"id": "kb2", | |
"subgroup" : [{"name" : "ketchup", "id": "ketchu2"}, {"name" : "chilli", "id": "chilli2"}] | |
}] | |
}); |
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'; | |
export function not(params/*, hash*/) { | |
return !params[0]; | |
} | |
export default Ember.Helper.helper(not); |
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
body { | |
margin: 12px 16px; | |
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
font-size: 12pt; | |
} | |
.checkboxhandler{ | |
position: relative; | |
margin-left: 10px; | |
margin-bottom:10px; | |
border: 1px solid red; | |
} |
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 Application from '../app'; | |
import config from '../config/environment'; | |
import { setApplication } from '@ember/test-helpers'; | |
import { start } from 'ember-qunit'; | |
import { assign } from '@ember/polyfills'; | |
let attributes = assign({ rootElement: '#main' }, config.APP); | |
setApplication(Application.create(attributes)); | |
start(); |
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 { module, test, skip } from 'qunit'; | |
import { check, didChange } from 'twiddle/utils/tree-helpers'; | |
const options = [{ | |
id: 1, | |
label: 'burger', | |
checked: false, | |
children: [{ | |
id: 3, | |
label: 'tomato', | |
checked: false | |
}, { | |
id: 4, | |
label: 'lettus', | |
checked: false | |
}, { | |
id: 5, | |
label: 'pickle', | |
checked: false | |
}] | |
}, { | |
id: 2, | |
label: 'kebab', | |
checked: false, | |
children: [{ | |
id: 6, | |
label: 'ketchup', | |
checked: false | |
}, { | |
id: 7, | |
label: 'chilli', | |
checked: false | |
}] | |
}]; | |
module('utils:tree-helper | didChange', function() { | |
test('detects one level of change', function(assert) { | |
const a = { checked: true }; | |
const b = { checked: false }; | |
const result = didChange(a, b); | |
assert.ok(result); | |
}); | |
test('detects a change in a child', function(assert) { | |
const a = { checked: false, children: [{ checked: true }] }; | |
const b = { checked: false, children: [{ checked: false }] }; | |
const result = didChange(a, b); | |
assert.ok(result); | |
}); | |
test('detects a change on an array', function(assert) { | |
const a = [{ checked: true }, { checked: false }]; | |
const b = [{ checked: true }, { checked: true }]; | |
const result = didChange(a, b); | |
assert.ok(result); | |
}); | |
}); | |
module('utils:tree-helper | check', function() { | |
test('it checks the node', function(assert) { | |
const result = check(options, 1); | |
assert.ok(result[0].checked, 'burger is checked'); | |
}); | |
module('a sibling is checked', function(hooks) { | |
let tree; | |
hooks.beforeEach(function(assert) { | |
tree = check(options, 1); | |
assert.ok(tree[0].checked, 'burger is checked'); | |
}); | |
module('another sibling is checked', function(hooks) { | |
hooks.beforeEach(function(assert) { | |
tree = check(tree, 2); | |
}); | |
test('the first sibling remains checked', function(assert) { | |
assert.ok(tree[0].checked, 'burger is checked'); | |
}); | |
}); | |
module('and children are checked before checking the other sibling', function(hooks) { | |
hooks.beforeEach(function(assert) { | |
tree = check(tree, 3); | |
assert.ok(tree[0].children[0].checked, 'tomato is checked'); | |
tree = check(tree, 2); | |
assert.ok(tree[1].checked, 'kebab is checked'); | |
}); | |
skip('unchecks the entire first tree', function(assert) { | |
assert.notOk(tree[0].checked, 'burger is not checked'); | |
assert.notOk(tree[0].children[0].checked, 'tomato is not checked'); | |
}); | |
}); | |
}); | |
}); | |
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.15.0", | |
"EmberENV": { | |
"FEATURES": {} | |
}, | |
"options": { | |
"use_pods": false, | |
"enable-testing": true | |
}, | |
"dependencies": { | |
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js", | |
"ember": "3.4.1", | |
"ember-template-compiler": "3.4.1", | |
"ember-testing": "3.2.2" | |
}, | |
"addons": { | |
"ember-decorators": "2.0.0" | |
} | |
} |
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
const toggle = value => !value; | |
const disable = () => false; | |
// the roots / siblings are contained by arrays | |
export function check(tree, id, transform = toggle) { | |
if (tree === undefined) return undefined; | |
if (Array.isArray(tree)) { | |
return tree.map(t => check(t, id, transform)); | |
} | |
if (tree.id === id || id === 'all') { | |
return checkNode(tree, id, transform); | |
} | |
if (tree.children) { | |
return checkChildren(tree, id, transform); | |
} | |
return tree; | |
} | |
function selectOnlySubtree(tree, id, transform) { | |
return tree.map(subTree => { | |
const newTree = check(subTree, id, transform); | |
if (!newTree.children || (transform !== disable && didChange(newTree, subTree))) { | |
return newTree; | |
} | |
return disableTree(subTree); | |
}); | |
} | |
function isTargetAtThisLevel(tree, id) { | |
return tree.map(t => t.id).includes(id); | |
} | |
function checkNode(tree, id, transform) { | |
return { | |
...tree, | |
checked: transform(tree.checked), | |
children: disableTree(tree.children) | |
}; | |
} | |
function disableTree(tree) { | |
return check(tree, 'all', disable); | |
} | |
function checkChildren(tree, id, transform) { | |
const newChildren = check(tree.children, id, transform); | |
const changed = didChange(tree.children, newChildren); | |
const checked = changed ? false : ( | |
id === 'all' ? transform(tree.checked) : tree.checked | |
); | |
return { | |
...tree, | |
checked: checked, | |
children: check(tree.children, id, transform) | |
}; | |
} | |
export function didChange(treeA, treeB) { | |
const rootsChanged = treeA.checked !== treeB.checked; | |
if (rootsChanged) return true; | |
if (Array.isArray(treeA) && Array.isArray(treeB)) { | |
return didChangeList(treeA, treeB); | |
} | |
if (treeA.children && treeB.children) { | |
return didChangeList(treeA.children, treeB.children); | |
} | |
return false; | |
} | |
function didChangeList(a, b) { | |
const compares = a.map((childA, index) => { | |
return didChange(childA, b[index]); | |
}); | |
const nothingChanged = compares.every(v => v === false); | |
return !nothingChanged; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment