Skip to content

Instantly share code, notes, and snippets.

@visualjeff
Last active September 12, 2016 18:16
Show Gist options
  • Save visualjeff/abde9f24b58c722e15454e971ab3ed77 to your computer and use it in GitHub Desktop.
Save visualjeff/abde9f24b58c722e15454e971ab3ed77 to your computer and use it in GitHub Desktop.
New Twiddle
import Ember from 'ember';
const {$}= Ember; //JQuery reference for events
import layout from '../templates/components/checkbox-component';
const {
Component,
get
} = Ember;
const MyComponent = Ember.Component.extend({
layout,
tagName: 'label',
classNames: ['checkbox-component'],
init() {
this._super(...arguments);
Ember.debug('init fired');
},
didInsertElement() {
Ember.debug('didInsertElement fired');
},
actions: {
toggleChecked() {
Ember.debug(`${this.get('text')} was clicked`);
let checked = get(this, 'checked');
this.set('checked', !checked);
checked = get(this, 'checked');
Ember.debug(`${checked}`);
//this.sendAction('update', !checked);
}
}
});
MyComponent.reopenClass({
positionalParams: ['checked', 'text']
});
export default MyComponent;
import Ember from 'ember';
export default Ember.Component.extend({
});
import Ember from 'ember';
export default Ember.Component.extend({
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
isProcessing: false,
isDirty: true,
initialized: false, //Set to true afterRender
/*
Reminder: computedProperties are cached unless what they watch is been updated via a set.
*/
proxiedModel: Ember.computed.map('model.vendorEntitlements.applications', function(model) {
var self = this;
// Pre-render setup: Check entitlements where the user already has an entitlement.
Ember.debug(" application entitlements: " + JSON.stringify(model.entitlements));
model.entitlements.forEach(function(entitlement) {
var userEntitlements = self.get('model.user.entitlements');
userEntitlements.forEach(function(userEntitlement) {
if ((userEntitlement.entitlementId === entitlement.id) &&
(userEntitlement.vendorId === self.get('model.vendor.id'))){
Ember.debug(" For vendor: " + self.get('model.vendor.id')+ ", " + userEntitlement.entitlementId + " === " + entitlement.id);
Ember.debug(" So lets check: " + entitlement.displayName);
Ember.set(entitlement, 'checked', true);
}
});
});
// Pre-render setup: if application has more than one entitlement AND the first entitlement in the array
// is enabled then enable the rest of the entitlement elements for that application.
if (model.entitlements.length > 1) {
if (!model.entitlements[0].checked) {
model.entitlements.forEach(function(entitlement, index /*, array */) {
if (index !== 0) {
Ember.debug(model.entitlements[0].id + " is not checked. So disable its children.");
Ember.set(entitlement, 'disabled', true);
}
});
}
}
//Post-render behavior
var objectProxyWithComputedProperty = Ember.ObjectProxy.extend({
resetIsDirty: function() {
Ember.run.scheduleOnce('afterRender', this, function() {
self.set('isDirty', false);
self.set('initialized', true);
});
}.on('init'), //On init object creation resets the isDirty flag to false.
content: {
id: model.id,
displayName: model.displayName,
entitlements: model.entitlements
},
/* Prevents checkbox changes in processChange from firing another processChange event
applyBefore: function() {
var currentContent = this.get('content');
currentContent.entitlements.removeArrayObserver(this); // Turn observer off
}.observesBefore('[email protected]'),
*/
/* Processes rules associated with click events. */
processChange: function() {
Ember.debug("processChange fired because of an event");
var currentContent = this.get('content');
//On click if more then one element is in the array check the following two things. Otherwise exit!
//1. If a user sets checked for the first element to true.
// toggle all of the other elements to enabled.
//2. If a user sets checked for the first element to false
// toggle all of following elements to false and disabled
if (currentContent.entitlements.length > 1) {
//Ember.debug("More than one element in array");
if (currentContent.entitlements[0].checked){
//Ember.debug("First element is checked");
currentContent.entitlements.forEach(function(entitlement, index /*, array */) {
if (index !== 0) {
Ember.debug(`Enabling ${JSON.stringify(entitlement)} checkboxes`);
Ember.set(entitlement, 'disabled', false); // Enable checkbox
}
});
} else {
Ember.debug("First element is NOT checked");
currentContent.entitlements.forEach(function(entitlement, index /*, array */) {
if (index !== 0) {
Ember.debug(`Unchecking and Disabling ${JSON.stringify(entitlement)} checkboxes`);
if (entitlement.checked) {
Ember.set(entitlement, 'checked', false); //Flip checked status
}
Ember.set(entitlement, 'disabled', true); //Disable checkbox
}
});
}
}
currentContent.entitlements.addArrayObserver(this); //Turn back observer on
if (self.get('initialized')) {
self.set('isDirty', true); //Set property so button will be re-evaluated
}
},
/* Fires on user checkbox selection */
apply: function() {
Ember.debug("==> Checkbox selected. Event fired! <==");
//You could short-circuit processChange? If the first checkbox
//isn't the one who cause this event to fire. Then there is no need to
//call processChange.
//let applications = self.get("model.vendorEntitlements.applications");
//applications.forEach(function(application) {
//Ember.debug(application.displayName);
//if checkbox clicked isn't the first in the array then shortcircuit
//});
Ember.run.once(this, 'processChange'); //Ensures observer event is handled once
}.observes('[email protected]') //Observices checkbox properties
});
return objectProxyWithComputedProperty.create();
}),
/*
Computed property watches two properties and is expected to change if either property changes. Do not use Ember.run.once here.
*/
buttonEnabled: Ember.computed('isDirty', 'isProcessing', 'initialized', function() {
Ember.debug('==> buttonEnabled fired!!!');
if (this.get('isDirty')) {
this.set('isDirty', false);
if (this.get('isProcessing')) {
return true; //Disable button, model is dirty AND we're in-flight.
}
/*
var group = $('.checkbox-group'); //Get checkbox group from DOM
*/
var checkBoxCount = 0;
this.get('proxiedModel').forEach(function(model){
checkBoxCount = checkBoxCount + model.get('content.entitlements').filterBy("checked", true).get("length");
});
if (checkBoxCount===0) {
// group.find('.errorMessage').addClass('error'); //Normally foundation abide would do this.
return true; //If nothing is checked then disable button.
}
// group.find('.errorMessage').removeClass('error'); //Normally foundation abide would do this.
return false; //Enable button, data is dirty but not in-flight.
} else {
return true; //Disable button, model is not dirty
}
}),
actions: {
saveChanges: function(model){
Ember.debug('saveChanges fired!');
}
}
});
import Ember from 'ember';
export default Ember.Route.extend({
model() {
let model = {};
model.checkboxes = [{
id: 1,
description: "checkbox 1",
checked: false
}, {
id: 2,
description: "checkbox 2",
checked: true
}, {
id: 3,
description: "checkbox 3",
checked: false
}];
model.vendorEntitlements = {};
model.vendorEntitlements.applications = [{
id: "PD",
displayName: "Payer Direct",
description: "SAP Vendor Portal Web Application",
entitlements: [{
id: "PD-User",
displayName: "Standard User",
description: "Standard user privileges"
}, {
id: "PD-SubmitClaims",
displayName: "Submit Claims",
description: "Ability to submit claims for a vendorId",
prerequisiteEntitlementIds: ["PD-User"]
}]
}, {
id: "EAM",
displayName: "Extranet Admin Maintenance",
description: "Vendor User Profile and Entitlements Maintenance",
entitlements: [{
id: "EAM-VendorAdmin",
displayName: "Vendor Admin",
description: "Ability to administer user entitlements for a vendorId"
}]
}, {
id: "WH",
displayName: "Work Hours",
description: "Super awesome Work Hours Web Application",
entitlements: [{
id: "WH-User",
displayName: "Standard WH User",
description: "Standard user privileges"
}, {
id: "WH-SubmitHours",
displayName: "Submit Hours",
description: "Ability to submit hours",
prerequisiteEntitlementIds: ["WH-User"]
},{
id: "WH-AdminHours",
displayName: "Administer Hours",
description: "Ability to administer hours",
prerequisiteEntitlementIds: ["WH-User"]
}]
}, {
id: "BPM",
displayName: "Extranet Account Maintenance",
description: "BPM",
entitlements: [{
id: "BPM-User",
displayName: "BPM-User",
description: "BPM-User"
}]
}];
model.vendor = {} ;
model.vendor.id = "654321-1";
model.user = {
profile: {
id: "1-2-3-12345677-234512345-65-34223561",
firstName: "Sally",
lastName: "Testa",
email: "[email protected]",
phoneNumber: "+1 4253556789 x1"
},
costcoEmployee: false,
totalAdministeredVendors: 0,
entitlements: [{
vendorId: "654321-1",
entitlementId: "BPM-User"
}, {
vendorId: "654321-1",
entitlementId: "PD-User"
}, {
vendorId: "654321-1",
entitlementId: "PS-SubmitClaims"
}, {
vendorId: "654321-1",
entitlementId: "EAM-VendorAdmin"
}],
createdDateTime: "2008-08-06T07:17:00-07:00",
modifiedDateTime: "2011-12-24T18:49:17",
acceptedDocuments: [{
id: "ExtranetTermsAndConditions_2014-01-01.pdf",
acceptedDateTime: "2005-01-21T15:35:36-08:00"
}]
};
return model;
}
});
1. Create a component for each checkbox group. Each group would have a parent child relationship between its own checkboxes.
2. Move proxiedModel (data for the checkboxes) into this new checkbox group and out of the controller.
3. Model would be passed in as is to the checkbox group component.
4. Nothing button related would be in the checkbox component.
<h1>Checkbox Component Playground</h1>
<br>
<br>
{{outlet}}
<form {{action "saveChanges" proxiedModel on="submit"}}>
{{#each proxiedModel as | application |}}
<label for={{application.id}}>
<strong>{{application.displayName}}</strong>
</label>
<ul>
{{#each application.entitlements as | entitlement |}}
{{#if entitlement.prerequisiteEntitlementIds.length}}
<li>{{checkbox-component
checked=entitlement.checked
text=entitlement.displayName
id=entitlement.id
disabled=entitlement.disabled
}}
</li>
{{else}}
<li>{{checkbox-component
checked=entitlement.checked
text=entitlement.displayName
id=entitlement.id
disabled=entitlement.disabled
}}
</li>
{{/if}}
{{/each}}
</ul>
{{/each}}
<button type=submit disabled={{buttonEnabled}}>submit</button>
</form>
<br>
<br>
<input type="checkbox"
id={{id}}
checked={{checked}}
onchange={{action "toggleChecked" value="target.value"}}
disabled={{disabled}}
/>
{{text}}
<label for={{entity.id}}>
<strong>{{entity.displayName}}</strong>
</label>
<ul>
{{#each entity.entitlements as | entitlement |}}
{{#if entitlement.prerequisiteEntitlementIds.length}}
<li>{{checkbox-component
checked=entitlement.checked
text=entitlement.displayName
id=entitlement.id
disabled=entitlement.disabled
}}
</li>
{{else}}
<li>{{checkbox-component
checked=entitlement.checked
text=entitlement.displayName
id=entitlement.id
disabled=entitlement.disabled
}}
</li>
{{/if}}
{{/each}}
</ul>
{
"version": "0.10.4",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.7.0",
"ember-data": "2.7.0",
"ember-template-compiler": "2.7.0"
},
"addons": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment