Skip to content

Instantly share code, notes, and snippets.

@cburgdorf
Last active December 17, 2015 20:39
Show Gist options
  • Select an option

  • Save cburgdorf/5668949 to your computer and use it in GitHub Desktop.

Select an option

Save cburgdorf/5668949 to your computer and use it in GitHub Desktop.
angular.module('sdk.directives.ccVariantSelector', []);
angular.module('sdk.directives.ccVariantSelector')
.filter('ccVariantFilter', ['$filter', function($filter) {
'use strict';
return function(values, selectedValues, key) {
var selected = {},
applyFilters = false;
// reformat for built in filter and exclude current property
for (var property in selectedValues){
if (key!==property && selectedValues[property]!==null && selectedValues[property]!==undefined) {
selected['properties.' + property] = selectedValues[property];
applyFilters = true;
}
};
// extract available variants
var variants = applyFilters ? $filter('filter')(values, selected, true) : values;
// extract flat values for the curent property
var result = [];
variants.forEach(function(variant){
if (result.indexOf(variant.properties[key]) === -1 && variant.stock > 0){
result.push(variant.properties[key]);
};
});
return result;
};
}])
.directive('ccVariantSelector', function() {
'use strict';
return {
restrict: 'E',
replace: true,
scope: {
variants: '='
},
templateUrl: '../sdk/src/directives/ccVariantSelector/ccvariantselector.tpl.html',
link: function(scope, element, attrs){
// extract flat list of available properties
// maybe iterating on the first variant is enough ?
scope.properties = [];
scope.variants.forEach(function(variant){
for (var property in variant.properties){
if (scope.properties.indexOf(property) === -1){
scope.properties.push(property);
};
};
});
scope.selectedValues = {};
}
};
});
<div class="cc-variant-selector">
<select ng-repeat="property in properties"
class="cc-variant-selector-select"
name="{{property}}"
ng-model="selectedValues[property]"
ng-options="val for val in variants|ccVariantFilter:selectedValues:property">
<option value="">-- chose {{property}} --</option>
</select>
</div>
Ext.define('CouchCommerce.view.CustomAttributesPane', {
extend: 'Ext.form.FieldSet',
xtype: 'customattributespane',
requires: [
'Ext.form.FieldSet'
],
config: {
layout: 'vbox',
cls: 'cc-custom-attributes-pane',
//Don't make that 'null' Sencha has a bug that will prevent
// the picker from working
selectboxNullValue: CouchCommerce.Lang.getNoSelection(),
selectboxNullValueText: CouchCommerce.Lang.getNoSelection(),
variants: [
// {
// variantID: 1,
// stock: 1,
// properties: {
// color: 'red',
// size: 'XL',
// zipside: 'left'
// }
// },
// {
// variantID: 2,
// stock: 1,
// properties: {
// color: 'green',
// size: 'XL',
// zipside: 'right'
// }
// },
// {
// variantID: 3,
// stock: 1,
// properties: {
// color: 'green',
// size: 'L',
// zipside: 'left'
// }
// }
]
},
/**
* @public
* get a validation object with an boolean success property and an
* invalidKeys property holding all invalid keys
*/
getValidations: function(){
var invalidInputs = [];
for (var key in this._variantsHashSet){
if (this[key].getValue() === this.getSelectboxNullValue()){
invalidInputs.push(key);
}
}
return {
success: invalidInputs.length === 0,
invalidKeys: invalidInputs
};
},
/**
* @public
* get the choosen variant
*/
getValue: function(){
var me = this;
var hashSet = me._variantsHashSet;
var filteredVariants = me
.getVariants()
.filter(function(item){
for (var key in hashSet){
if (item.properties[key] !== me[key].getValue()){
return false;
}
}
return true;
});
return filteredVariants.length > 0 ? filteredVariants[0] : null;
},
/**
* @private
* Renders all needed selectboxes every time the variants change
*/
updateVariants: function(oldValue, newValue){
var me = this;
me.removeAll(true);
var variants = me.getVariants();
var hashSet = me._variantsHashSet = this._variantsToHashset(variants);
var hashSetItemCount = 0;
for (var key in hashSet){
hashSetItemCount++;
var selectItems = me._hashSetItemToSelectEntries(hashSet[key]);
me[key] = me.add({
xtype: 'selectfield',
ui: 'couch-default',
label: key,
labelWidth: 120,
height: 40,
//usePicker:true,
options: selectItems,
placeHolder: key,
name: key,
defaultPhonePickerConfig: {
cancelButton: CouchCommerce.Lang.getBtnCancel(),
doneButton: CouchCommerce.Lang.getBtnDone()
}
});
me[key].on('change', me._onValueSelected, me);
}
me._filterBoxes();
//Todo: Figure out what's best to calculate the size for now
//let's just assume X times the size of what
//Sencha uses as default for select boxes
me.setHeight(hashSetItemCount * 2.5 + 'em');
},
_onValueSelected: function(origin, newValue, oldValue, eOpts){
this._filterBoxes();
//based on the current filter, get all matching variants
var variants = this._getFilteredVariantsWithoutFilterFor('');
//And pick the first match or raise with null
var matchingVariant = variants.length > 0 ? variants[0] : null;
this.fireEvent('variantchanged', this, matchingVariant);
},
/**
* @private
* Filters the data of each select box according
// to what should be currently valid
*/
_filterBoxes: function(){
var me = this;
//This method triggers change events itself so we need to asure
// we don't get into an invinite loop
if (me._updatingEntries){
return;
}
me._updatingEntries = true;
var hashSet = me._variantsHashSet;
//loop through each variant
for (var key in hashSet){
//get all variant items that are valid. Filter only by all
// other variant keys (NOT by the current key)
var filteredItems = me._getFilteredVariantsWithoutFilterFor(key);
if (filteredItems.length === 0){
me[key].setOptions({
text: this.getSelectboxNullValueText(),
value: this.getSelectboxNullValue()
});
continue;
}
//transform the filtered variant items into a hashset
var tempHashset = me._variantsToHashset(filteredItems);
//create selectbox entries for this variant property
var selectItems = me._hashSetItemToSelectEntries(tempHashset[key]);
//set the options for the current variant property
me[key].setOptions(selectItems);
}
me._updatingEntries = false;
},
/**
* @private
* Filters the variants by all the values that are
* chosen in the selectboxes *except one* which is specified by the
* excludeFilter parameter
*/
_getFilteredVariantsWithoutFilterFor: function(excludedFilter){
var me = this;
var hashSet = me._variantsHashSet;
var selectBoxNullValue = me.getSelectboxNullValue();
var filteredVariants = me.getVariants()
.filter(function(item){
if (item.stock <= 0){
return false;
}
for (var key in hashSet) {
if (key === excludedFilter){
continue;
}
var selectBoxValue = me[key].getValue();
if (selectBoxValue !== selectBoxNullValue){
if (item.properties[key] !== selectBoxValue){
return false;
}
}
}
return true;
});
return filteredVariants;
},
/**
* @private
* Takes an array of variants and returns a hashset where each key
* is a variant and the value
* is an array of the items that are legal for the variant
*/
_variantsToHashset: function(attributes){
//generate a hashset for all custom attributes
var hashSet = {};
attributes.forEach(function(value){
for (var property in value.properties){
var entry = value.properties[property];
if (!hashSet[property]){
hashSet[property] = [entry];
}
else if (!Ext.Array.contains(hashSet[property], entry)){
hashSet[property].push(entry);
}
}
});
return hashSet;
},
/**
* @private
* Takes an array of strings and returns an array of objects with a key
* and a value. Those can be used as entries
* for the selectfield
*/
_hashSetItemToSelectEntries: function(hashSetItem){
var items = Ext.Array.map(hashSetItem, function(item){
return {
text: item,
value: item
};
});
return [{
text: this.getSelectboxNullValueText(),
value: this.getSelectboxNullValue()
}].concat(items);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment