Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save theoldcounty/d507d9ff2d7802fd0a4ee946a474dee9 to your computer and use it in GitHub Desktop.

Select an option

Save theoldcounty/d507d9ff2d7802fd0a4ee946a474dee9 to your computer and use it in GitHub Desktop.
Parent / Child Component Communication
import Component from '@ember/component';
import { action, computed } from '@ember-decorators/object';
import { check } from 'twiddle/utils/tree-helpers';
export default class extends Component {
selectedItems= [];
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(item, event) {
console.log("clicked", item);
console.log("event", event.target.checked);
let selected = event.target.checked;
if (selected) {
this.get('selectedItems').pushObject(item);
} else {
this.get('selectedItems').removeObject(item);
}
console.log("selectedItems", this.get('selectedItems'));
const newTree = check(this.options, item.id);
this.set('options', newTree);
}
}
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"}]
}]
});
import Ember from 'ember';
export function not(params/*, hash*/) {
return !params[0];
}
export default Ember.Helper.helper(not);
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 grey;
}
<h1>Welcome to {{appName}}</h1>
<br>
<WrappingComponent as |options toggle|>
{{#each options as |item|}}
<CheckboxGroup @item={{item}} @onClick={{toggle}} />
{{/each}}
</WrappingComponent>
<br>
{{outlet}}
<br>
<br>
<div class="checkboxhandler">
<input
type="checkbox"
checked={{@item.checked}}
onclick={{action @onClick @item}}
>
<label>{{@item.label}} -- checked: {{@item.checked}}</label>
{{#if @item.children}}
{{#each @item.children as |child|}}
<CheckboxGroup @item={{child}} @onClick={{@onClick}} />
{{/each}}
{{/if}}
</div>
{{yield this.options (action this.itemSelected)}}
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();
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');
});
});
});
});
{
"version": "0.15.0",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"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"
}
}
const toggle = value => !value;
const disable = () => false;
export function check(tree, id, transform = toggle) {
// the roots / siblings are contained by arrays
if (Array.isArray(tree)) {
// the "UX" logic, as @TheOldCountry would say
// check to see if this level in the tree is where
// the change will be
const atThisLevel = tree.map(t => t.id).includes(id);
if (atThisLevel) {
console.log("at level")
return tree.map(subTree => {
const newTree = check(subTree, id, transform);
if (didChange(newTree, subTree)) {
return newTree;
}
return check(subTree, '', disable);
});
return result;
}
// not at this level
return tree.map(t => check(t, id, transform));
}
if (tree.id === id) {
const newTree = {
...tree,
checked: transform(tree.checked),
};
if (newTree.children) {
newTree.children = check(newTree.children, '', disable);
}
return newTree;
}
if (tree.children) {
return {
...tree,
checked: id === '' ? transform(tree.checked) : tree.checked,
children: check(tree.children, id, transform)
};
}
return tree;
}
function didChange(treeA, treeB) {
return treeA.checked !== treeB.checked;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment