Skip to content

Instantly share code, notes, and snippets.

@leofrozenyogurt
Created July 8, 2015 21:09
Show Gist options
  • Save leofrozenyogurt/5e2284aa2b1c7c0f3755 to your computer and use it in GitHub Desktop.
Save leofrozenyogurt/5e2284aa2b1c7c0f3755 to your computer and use it in GitHub Desktop.
/**
* Author: Derek Gould
* Date: 8/19/13
* Time: 2:44 PM
*/
angular.module('vr.directives.nlForm', ['vr.directives.nlForm.select', 'vr.directives.nlForm.text']);
angular.module('vr.directives.nlForm.select',[])
.directive('nlSelect', function(){
return {
restrict: 'EA',
replace: true,
scope: {
value: '=',
options: '='
},
controller: 'nlSelectCtrl',
template:
"<div ng-form='nlSelect' class='nl-field nl-dd' ng-class=\"{'nl-field-open': opened}\">" +
"<a class='nl-field-toggle' ng-click='open($event)' ng-bind='getSelected()'></a>" +
"<ul>" +
"<li ng-repeat='label in getLabels()' ng-class=\"{'nl-dd-checked': isSelected(label)}\" ng-click='select(label); initializeSecond(value)' ng-bind='label'></li>" +
"</ul>" +
"</div>",
link: function(scope, element, attributes){
// is this required
scope.required = !angular.isUndefined(attributes.required);
// allow multiple options to be selected
scope.multiple = !angular.isUndefined(attributes.multiple);
// text for the view when multiple options are selected
scope.conjunction = scope.multiple && attributes.multiple != ''?attributes.multiple:'and';
// text for the view when no options are selected
scope.none = !angular.isUndefined(attributes.empty)?attributes.empty:'none';
// convert the value to an array if this is a multi-select
if(scope.multiple && !angular.isArray(scope.value)) {
scope.value = [scope.value];
}
var overlay = false;
//look for an overlay element
angular.forEach(element.parent().children(), function(child){
child = angular.element(child);
if(child.hasClass('nl-overlay')){
overlay = child;
}
});
if(!overlay){
// no overlay exists so create one
overlay = angular.element('<div class="nl-overlay"></div>');
element.parent().append(overlay);
}
// close the select when the overlay is clicked
overlay.bind('click',function() { scope.$apply(scope.close); });
}
};
})
.controller('nlSelectCtrl', ['$scope','$http', 'filterFilter','$resource', function nlSelectCtrl($scope, $http, filterFilter, $resource) {
// this was the old controller
$scope.initializeScopes = function() {
$scope.searchBy = [
{value: "groups",label: 'CFM Recommendations'},
{value: "allergens",label: 'Allergens'},
{value: "categories",label: 'Products'}
];
$http.get("/categories.json" ).success(function(data) {
$scope.allergens = data.categories //sets this data
}).error(function(data, status, headers, config) {});
$scope.times = [
{ value: 'any', label: 'anytime' },
{ value: '19:00', label: 'at 7 p.m.' },
{ value: '20:00', label: 'at 8 p.m.' },
{ value: '21:00', label: 'at 9 p.m.' }
];
$scope.answers = {
searchBy: 'groups',
style: 'ingredient',
time: '19:00',
city: ''
};
}
$scope.subline = "For example: <em>Los Angeles</em> or <em>New York</em>";
$scope.initializeItems = function(list) {
if (list) {
var listUrl =list
}
else{
listUrl ="ingredients"
}
$http.get("/"+listUrl+".json" ).success(function(data) {
$scope.firstValues = data; //sets this data
}).error(function(data, status, headers, config) {});
}
$scope.initializeAllergens = function(list) {
$http.get("/allergens.json" ).success(function(data) {
$scope.allergens = data; //sets this data
}).error(function(data, status, headers, config) {});
}
$scope.initializeCategories = function(list) {
$http.get("/categories.json" ).success(function(data) {
$scope.categories = data; //sets this data
}).error(function(data, status, headers, config) {});
}
$scope.initializeAnd = function(id){
$('.and').show();
}
$scope.initializeSecond = function(list) {
// clear the entire form before setting it again
// $(':input', '.simple_form').each(function() {
// this.value = "";
// });
// change the list based on what is selected
if (list) {
$('#second').show();
var listUrl =list
}
else{
listUrl ="ingredients"
}
$http.get("/"+listUrl+".json" ).success(function(data) {
console.log(list);
if (list == "allergens" || list == "groups"){
$scope.queryText = "I want to avoid";
console.log("hit me");
}
else{
$scope.queryText = "I'm looking for a ";
}
$scope.secondValues = $scope.allergens //sets this data
}).error(function(data, status, headers, config) {});
}
///
// init all the scopes
// $scope.initializeItems();
$scope.initializeScopes();
$scope.initializeSecond();
// $scope.initializeAllergens();
// $scope.initializeCategories();
// selected allergens
$scope.selection = [];
// helper method to get selected allergens
// $scope.selectedAllergens = function selectedAllergens() {
// return filterFilter($scope.allergens, { selected: true });
// };
// Check all
$scope.clearAll = function () {
$scope.selectedAll = false;
angular.forEach($scope.allergens, function (allergen) {
allergen.selected = $scope.selectedAll;
});
};
// option list type constants
var ARRAY_OF_LABELS = 1; // e.g. [ 'one', 'two', 'three', ...]
var ARRAY_OF_OBJECTS = 2; // e.g. [ { label: 'one', value: 'ten'}, { label: 'two', value: 'nine'}, ...]
var OBJECT_OF_VALUES = 3; // e.g. { 'one':'ten', 'two':'nine', 'three':'eight', ...}
var OBJECT_OF_OBJECTS = 4; // e.g. { 'one':{ label: 'one', value: 'ten'}, 'two':{ label: 'two', value: 'nine' }, ...}
// is the select open
$scope.opened = false;
// is the value in the list of options
function isOption(value) {
var found = false;
angular.forEach($scope.options,function(opt) {
switch($scope.optionType) {
case ARRAY_OF_LABELS:
case OBJECT_OF_VALUES:
if(value == opt) {
found = true;
}
break;
case ARRAY_OF_OBJECTS:
case OBJECT_OF_OBJECTS:
if(value == opt.value) {
found = true;
}
break;
}
});
return found;
}
function optionsLength() {
switch($scope.optionType) {
case ARRAY_OF_LABELS:
case ARRAY_OF_OBJECTS:
return $scope.options.length;
case OBJECT_OF_OBJECTS:
case OBJECT_OF_VALUES:
var ctr = 0;
angular.forEach($scope.options, function() { ctr++; });
return ctr;
}
return 0;
}
// get the option at the given index, normalized as an object: { value: 'value', label: 'label' }
function getOption(index) {
if(index < optionsLength() && index >= 0) {
switch($scope.optionType) {
case ARRAY_OF_LABELS:
// the label and value are the same
return { value: $scope.options[0], label: $scope.options[0] };
case ARRAY_OF_OBJECTS:
// already normalized
return $scope.options[0];
case OBJECT_OF_VALUES:
case OBJECT_OF_OBJECTS:
// iterate through the options to find the index
var option = null;
var ctr = 0;
angular.forEach($scope.options,function(value, label) {
if(ctr == index) {
if($scope.optionType == OBJECT_OF_VALUES) {
option = { value: value, label: label };
} else {
option = value;
}
}
ctr++;
});
return option;
}
}
return { value: '', label: ''};
};
// get the label from the given value
function getLabel(value) {
var label = value;
switch($scope.optionType) {
case ARRAY_OF_OBJECTS:
case OBJECT_OF_OBJECTS:
// find the option with the given value and get its value
angular.forEach($scope.options, function(opt) {
if(opt.value == value) {
label = opt.label;
}
});
break;
case ARRAY_OF_LABELS:
// the label is the value so don't do anything
break;
case OBJECT_OF_VALUES:
// find the option with the given value and get the index (the label)
angular.forEach($scope.options, function(opt, index) {
if(value == opt) {
label = index;
}
});
break;
}
return label;
};
// get the value given the label
function getValue(label) {
var value = label;
switch($scope.optionType) {
case ARRAY_OF_LABELS:
// the value is the label so don't do anything
break;
case ARRAY_OF_OBJECTS:
// find the option with the given label and get its value
angular.forEach($scope.options,function(opt) {
if(opt.label == label) {
value = opt.value;
}
});
break;
case OBJECT_OF_VALUES:
// simple index retrieval
value = $scope.options[label];
break;
case OBJECT_OF_OBJECTS:
// simple index retrieval
value = $scope.options[label].value;
break;
}
return value;
};
// check to make sure all the values are in the list of options
function checkValue() {
if($scope.multiple) {
var values = [];
angular.forEach($scope.value, function(value) {
if(isOption(value)) {
values.push(value);
}
});
$scope.value = values;
} else {
if(!isOption($scope.value)) {
$scope.value = getOption(0).value;
}
}
};
// open the select
$scope.open = function(event){
event.stopPropagation();
$scope.opened = true;
};
// close the select
$scope.close = function(){
$scope.opened = false;
};
// select an option
$scope.select = function(option) {
console.log(option)
$scope.setValue(option);
$scope.close();
};
// set the value, or add it to the list if this is a multi-select
$scope.setValue = function(option) {
var value = getValue(option);
if($scope.multiple) {
var index = $scope.value.indexOf(value);
if(index == -1) {
$scope.value.push(value);
} else {
$scope.value.splice(index,1);
}
if($scope.required) {
// at least one option must be selected
if($scope.value.length == 0) {
// no options selected so it's invalid
$scope.nlSelect.$setValidity('required',false);
} else {
// we're good here
$scope.nlSelect.$setValidity('required',true);
}
}
} else {
$scope.value = value;
}
};
// extract just the labels from the options
$scope.getLabels = function() {
switch($scope.optionType) {
case ARRAY_OF_LABELS:
// don't need to do anything
return $scope.options;
case ARRAY_OF_OBJECTS:
// map the array to pull out the label
return $scope.options.map(function(opt) {
return opt.label;
});
case OBJECT_OF_VALUES:
case OBJECT_OF_OBJECTS:
// iterate through the options to get the labels
var options = [];
angular.forEach($scope.options,function(value, label) {
if($scope.optionType == OBJECT_OF_VALUES) {
options.push(label);
} else {
options.push(value.label);
}
});
return options;
}
return [];
};
// concatenate the current selections for the view
$scope.getSelected = function() {
if($scope.multiple) {
// there might be multiple selections
var text = '';
if($scope.value.length > 0) {
// there is at least one selection
var comma = '';
var ctr = 1;
angular.forEach($scope.value, function(value) {
text += comma+getLabel(value);
ctr++;
if($scope.value.length > 2){
comma = ', ';
} else {
comma = ' ';
}
if(ctr == $scope.value.length) {
comma += $scope.conjunction+' ';
}
})
} else {
// no selections
text = $scope.none;
}
return text;
} else {
// only one selection possible
return getLabel($scope.value);
}
};
// check if the option is selected
$scope.isSelected = function(option) {
if($scope.multiple) {
return $scope.value.indexOf(getValue(option)) > -1;
} else {
return $scope.value == getValue(option);
}
};
// make sure we update the options internally if they change externally
$scope.$watch('options',function() {
// reset option list type
$scope.optionType = null;
if(angular.isArray($scope.options)) {
// option list is an array
if(angular.isObject($scope.options[0])) {
// of objects
$scope.optionType = ARRAY_OF_OBJECTS;
} else {
// of labels
$scope.optionType = ARRAY_OF_LABELS;
}
} else if(angular.isObject($scope.options)) {
// option list is an object
for(var key in $scope.options) {
if($scope.options.hasOwnProperty(key)) {
if(angular.isObject($scope.options[key])) {
// of objects
$scope.optionType = OBJECT_OF_OBJECTS;
} else {
// of key:value pairs
$scope.optionType = OBJECT_OF_VALUES;
}
break;
}
}
}
// make sure the value is still in the list of options
checkValue();
},true);
}]);
angular.module('vr.directives.nlForm.text',[])
.directive('nlText', function(){
return {
restrict: 'EA',
replace: true,
scope: {
placeholder: '@',
subline: '@',
name: '@',
value: '='
},
template:
'<div ng-form class="nl-field nl-ti-text" ng-class="{\'nl-field-open\': opened}">' +
'<a class="nl-field-toggle" ng-click="open($event)" ng-bind="viewValue()"></a>' +
'<ul>' +
'<li class="nl-ti-input">' +
'<input type="text" placeholder="{{ placeholder }}" name="{{ name }}" ng-model="value" ng-click="$event.stopPropagation()" ng-required="required"/>' +
'<button class="nl-field-go" ng-click="close()">Go</button>' +
'</li>' +
'<li class="nl-ti-example" ng-show="showSubline()" ng-bind-html-unsafe="subline"></li>' +
'</ul>' +
'</div>',
controller: 'nlTextCtrl',
link: function(scope, element, attributes){
// is this input required?
scope.required = !angular.isUndefined(attributes.required);
var overlay = false;
//look for an overlay element
angular.forEach(element.parent().children(), function(child){
child = angular.element(child);
if(child.hasClass('nl-overlay')){
overlay = child;
}
});
if(!overlay){
// no overlay exists so create one
overlay = angular.element('<div class="nl-overlay"></div>');
element.parent().append(overlay);
}
// close the input when the overlay is clicked
overlay.bind('click',function() { scope.$apply(scope.close) });
}
};
})
.controller('nlTextCtrl',['$scope', function($scope){
// is the input open
$scope.opened = false;
// open the input
$scope.open = function(event){
event.stopPropagation();
$scope.opened = true;
};
// close the input
$scope.close = function(){
$scope.opened = false;
$scope.initializeSecond();
};
// if there is no value, show the placeholder instead
$scope.viewValue = function(){
if($scope.value == ''){
return $scope.placeholder;
}
return $scope.value;
};
// do we have a subline? ok, then show it!
$scope.showSubline = function() {
return angular.isString($scope.subline) && $scope.subline != '';
};
}]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment