Last active
August 29, 2015 13:57
-
-
Save Deraen/9811993 to your computer and use it in GitHub Desktop.
angular-selectize.js
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
/* jshint camelcase: false */ | |
/* global $ */ | |
// TODO: multiple items | |
angular.module('fooApp') | |
.factory('autocompleteFactory', function() { | |
var factory = function(overwrites) { | |
return { | |
restrict: 'E', | |
replace: true, | |
template: '<div><input/></div>', | |
require: 'ngModel', | |
scope: { | |
completeObj: '=', | |
}, | |
link: function(scope, el, attrs, ctrl) { | |
var opts = _.extend({ | |
plugins: ['restore_on_backspace'], | |
maxItems: 1, | |
createOnBlur: true, | |
// This currently requires version from github: Deraen/selectize.js | |
blurOnEmptyReturn: true, | |
onChange: function(val) { | |
// Set selectize value to ng-model (input value-attr) (this is a string, id or multiple ids separater by delimeter) | |
ctrl.$setViewValue(val); | |
// Update object. And be sure to modify existing object insted of creating a new! | |
if (scope.completeObj) { | |
if (!val) { | |
for (var i in scope.completeObj) { | |
if (scope.completeObj.hasOwnProperty(i)) scope.completeObj[i] = null; | |
} | |
} else { | |
_.extend(scope.completeObj, this.options[val]); | |
} | |
} | |
}, | |
}, overwrites); | |
// Init | |
var $select = $('input', el).selectize(opts); | |
var selectize = $select[0].selectize; | |
// If ng-model (input el value-attr) changes | |
scope.$watch(function() { | |
return ctrl.$viewValue; | |
}, function(value) { | |
// If custom version of create function is provied, use that. | |
// Would be possible to use async maybe, but that might conflict with $watch('completeObj') | |
if (opts.createSync && !selectize.options[value]) { | |
selectize.addOption(opts.createSync(value)); | |
} | |
// This will do nothing if option doesn't exist | |
selectize.setValue(value); | |
}); | |
// If object is changed make sure that is used for selected item | |
scope.$watch('completeObj', function(obj) { | |
if (!obj) return; | |
// Create option if doesn't exist | |
selectize.addOption(obj); | |
// Update if exists | |
selectize.updateOption(obj[opts.valueField], obj); | |
// Make sure it's selected | |
selectize.setValue(obj[opts.valueField]); | |
}); | |
} | |
}; | |
}; | |
// Following are intented to be used with my Angular Api thingie. | |
// It should be easy to adapt these for $http or $resource... | |
// or just implement load and create manually for every autocomplete type. | |
factory.loadFn = function(load) { | |
return function(q, cb) { | |
load({}, {q: q}).success(function(data) { | |
cb(data.list); | |
}); | |
}; | |
}; | |
factory.createFn = function(parse, load) { | |
return function(input, cb) { | |
var obj = parse(input); | |
if (!obj) { | |
load({}, {q: input}).success(function(data) { | |
if (data.list.length === 1) cb(_.first(data.list)); | |
else cb(); | |
}); | |
} else { | |
cb(obj); | |
} | |
}; | |
}; | |
return factory; | |
}) | |
.directive('fooComplete', function(autocompleteFactory, Api) { | |
// It's not possible to use angular templates - but you should be using Lodash already... | |
var tpl = _.template('' + | |
'<div>' + | |
' <span class="code"><%- id %>,</span>' + | |
' <span class="name"><%- value %></span>' + | |
'</div>'); | |
var createTpl = _.template('' + | |
'<div class="create">' + | |
' <% if(!item) { %>To create new item write: "id, value"<% } else { %>' + | |
' Create item: <strong><%- item.id %></strong>, <%- item.value %>.<% } %>' + | |
'</div>'); | |
function parse(input) { | |
input = input.split(','); | |
return {id: input[0], value: input[1]}; | |
} | |
function getFoos(params, query, reqBody) { | |
return $http.get('/search', {params: query}); | |
} | |
// Some of options in this example are unnecessary... | |
return autocompleteFactory({ | |
load: autocompleteFactory.loadFn(getFoos), | |
create: autocompleteFactory.createFn(parse, getFoos), | |
valueField: 'id', | |
searchField: ['id', 'value'], | |
render: { | |
option: function(item) { return tpl(item); }, | |
item: function(item) { return tpl(item); }, | |
option_create: function(item) { return createTpl({item: parse(item)}); }, | |
} | |
}); | |
}) | |
// For angular-xeditable | |
.directive('editableFooComplete', function(editableDirectiveFactory) { | |
return editableDirectiveFactory({ | |
directiveName: 'editableFooComplete', | |
inputTpl: '<foo-complete/>', | |
}); | |
}); |
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
<foo-complete ng-model="id" complete-obj="obj"/> | |
<button ng-click="selectFoo()">Select something</button> | |
<p>ID: {{id}}</p> | |
<p>Obj: {{obj}}</p> |
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
angular.module('fooApp') | |
.controller('fooCtrl', function($scope) { | |
$scope.id = '1'; | |
$scope.obj = {id: '1', value: 'foo bar'}; | |
$scope.$watch('obj', function(val) { | |
console.log('Selected obj', val); | |
}); | |
$scope.selectFoo = function() { | |
$scope.id = '2'; // This can work if selectize.options already contains object with this id | |
... or | |
$scope.obj = {id: 2, value: 'another item'}; | |
}; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment