patternjavascriptMinor
Creating a symbol toolbar with Angular
Viewed 0 times
creatingsymbolwithangulartoolbar
Problem
I have been given a requirement to create a symbol toolbar, a toolbar where each button represents a unique symbol.
This is how the toolbar would work:
-
A user clicks inside a text field and enters data.
-
The user would then click a symbol on the toolbar and it will be appended to that specific text field.
-
The browser will put focus back on that text field.
I have created this toolbar, but I really dislike my implementation because it feels really hacky. In my implementation, I created two functions,
I feel like this is hacky because:
-
I have to use jQuery to re-focus on the text field.
-
I'm passing in a hardcoded string representing the field name (meaning if I change the name of the field and forget to change the hardcoded string, then this symbol feature will break for that specific text field).
This works fine now with a few text fields in which the users may want to append symbols, but now I'm learning I need to add the functionality to append symbols to text fields inside a whole Angular Ui-Grid (which exists inside a separate controller). So I am realizing I need to refactor this if I want this to work with a Ui-Grid as well. I know I need to move t
This is how the toolbar would work:
-
A user clicks inside a text field and enters data.
-
The user would then click a symbol on the toolbar and it will be appended to that specific text field.
-
The browser will put focus back on that text field.
I have created this toolbar, but I really dislike my implementation because it feels really hacky. In my implementation, I created two functions,
addSymbol and setLastFocused in my controller:$scope.addSymbol = function (field)
{
if (!$scope.product[$scope.lastFocusedModelKey])
{
$scope.product[$scope.lastFocusedModelKey] = "";
}
$scope.product[$scope.lastFocusedModelKey] = $scope.product[$scope.lastFocusedModelKey] + field.symbol.SymbolCharacter;
$('#' + $scope.lastFocusedModelKey).focus();
}
$scope.setLastFocused = function (lastFocusedModelKey)
{
$scope.lastFocusedModelKey = lastFocusedModelKey;
}SetLastFocused is called every time a user puts focus on a text field. I pass in a string of the field name like this:AddSymbol accepts the button field as a parameter, and appends the symbol to the model that is bound to the text field, and then re-focuses on the text field.I feel like this is hacky because:
-
I have to use jQuery to re-focus on the text field.
-
I'm passing in a hardcoded string representing the field name (meaning if I change the name of the field and forget to change the hardcoded string, then this symbol feature will break for that specific text field).
This works fine now with a few text fields in which the users may want to append symbols, but now I'm learning I need to add the functionality to append symbols to text fields inside a whole Angular Ui-Grid (which exists inside a separate controller). So I am realizing I need to refactor this if I want this to work with a Ui-Grid as well. I know I need to move t
Solution
With custom directives you could save the focus in a
The ID is generated with a counter that is incremented at every controller run of the
Please have a look at the code below (then it's more clear how it works, it's a bit difficult to describe) or in this jsfiddle.
The first focus is only working in jsfiddle if you open the fiddle in full screen mode. Not sure what's wrong.
$scope.focusTarget variable and the resetting of the focus can be done with a focus broadcast that have the instanceId (=focusTarget e.g. 1, 2, ...) and the new icon class so each directive called iconInput will receive the broadcast and check if the passed ID is matching. If it matches it applies the focus and sets the new icon class.The ID is generated with a counter that is incremented at every controller run of the
iconInput directive.Please have a look at the code below (then it's more clear how it works, it's a bit difficult to describe) or in this jsfiddle.
The first focus is only working in jsfiddle if you open the fiddle in full screen mode. Not sure what's wrong.
angular.module('demoApp', [])
.directive('iconbar', IconbarDirective)
.directive('iconInput', IconInputDirective)
.factory('focus', FocusFactory)
.controller('mainController', MainController);
function IconbarDirective(focus) {
return {
restrict: 'EA',
transclude: true,
scope: {
focusTarget: '@'
},
template: '',
link: function (scope, element) {
var icons = element.find('i');
console.log(icons);
icons.addClass('iconbar-icon');
element.find('i').bind('click', function (evt) {
console.log('clicked', evt.target, this);
var icon = angular.element(this),
iconClasses = icon[0].className.split('ng-scope'), // third is ng-scope
target = scope.focusTarget;
//console.log(iconClasses);
//console.log(iconClasses[0]);
focus('focus' + target, iconClasses[0]);
scope.$apply();
});
}
}
}
function IconInputDirective() {
var instanceCounter = 0;
return {
restrict: 'EA',
scope: {
target: '='
},
template: '' +
'' +
'',
controller: function ($scope) {
instanceCounter++;
this.instanceId = instanceCounter;
console.log('instance no.', instanceCounter);
$scope.placeholder = function() {
return $scope.icon || 'fa fa-bars icon-invisible';
};
},
link: function (scope, element, attr, ctrl) {
var inputBox = element.find('input');
inputBox.bind('focus', function () {
// clear other acitve classes
element.parent().find('input').removeClass('active');
inputBox.addClass('active');
scope.target = ctrl.instanceId;
scope.$apply();
})
/* .bind('blur', function () {
inputBox.removeClass('active');
});*/
// code for focusOn from here http://stackoverflow.com/questions/14833326/how-to-set-focus-on-input-field
scope.$on('focusOn', function (e, name, iconClass) {
console.log('focuson triggered', name, element[0]);
if (name === 'focus' + ctrl.instanceId) {
console.log('focus now!!', element.find('input')[0]);
element.find('input')[0].focus();
inputBox.addClass('active');
scope.icon = iconClass;
}
});
}
}
}
function MainController($scope, focus) {
$scope.focusTarget = 1; // last acitve input box --> sets first focus
focus('focus' + $scope.focusTarget); // activate focus with-out class
}
function FocusFactory($rootScope, $timeout) {
return function (name, iconClass) {
$timeout(function () {
$rootScope.$broadcast('focusOn', name, iconClass);
});
}
}
.iconbar-icon {
cursor: pointer;
}
.icon-placeholder {
width: 16px;
padding: 5px;
}
[iconbar] {
border: 1px solid;
padding: 5px;
margin-bottom: 5px;
}
.active {
border: 2px solid blue;
}
i {
padding-right: 5px;
}
.icon-invisible {
visibility: hidden;
}
/ spacer not working /
.icon-spacer::before,
.icon-blank::before {
width: 1em;
content: ' ';
}
Context
StackExchange Code Review Q#101302, answer score: 2
Revisions (0)
No revisions yet.