Set focus of text box in directive - angularjs

I'm experimenting with an inline-edit directive form here: http://icelab.com.au/articles/levelling-up-with-angularjs-building-a-reusable-click-to-edit-directive/
I would like to know how to set the cursor in the text box that gets created when I click some text to be edited.
Here is the directive with a few minor changes to the template:
.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled" ng-click="enableEditor()">' +
'{{value}} ' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue" ng-blur="save()">' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});

you need to add a link function like this :
link : function(scope, ele, attrs) {
scope.$watch('view.editorEnabled', function(n, o) {
if(n) ele.find('input')[0].focus();
})
}

Related

Modal not working properly

I am facing a problem with the pop up modal in Angularjs. I have a button and on clicking I need to show a modal. Here is my code. When I click on Details button for first time, the modal pop up appears but when I click again.. the app.directive doesn't get called. Greatly appreciate the help. Thanks.
JS:
myApp.directive('modal', function () {
return {
template: '<div class="modal fade">' +
'<div class="modal-dialog">' +
'<div class="modal-content">' +
'<div class="modal-header">' +
'<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>' +
'<h4 class="modal-title">{{ title }}</h4>' +
'</div>' +
'<div class="modal-body" ng-transclude></div>' +
'</div>' +
'</div>' +
'</div>',
restrict: 'E',
transclude: true,
replace:true,
scope:true,
link: function postLink(scope, element, attrs) {
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value){
if(value == true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).on('shown.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = true;
});
});
$(element).on('hidden.bs.modal', function(){
scope.$apply(function(){
scope.$parent[attrs.visible] = false;
});
});
}
};
});
.state("abc"){
controller:function(){
$scope.showModal = false;
$scope.toggleModal = function(){
$scope.showModal = false;
$scope.showModal = !$scope.showModal;
var aclpGuid = $stateParams.aclpGuid;
};
}
}
HTML:
<td>
<button ng-click="toggleModal()">Details</button>
<modal visible="showModal">
<label>Room Details</label>
</modal>
</td>
I guess the issue is the isolate scope which you have here scope:true inside the directive. Using this, the scope inside a directive is seperated from the scope outside. To confirm this I checked the scope variable with and without scope: true. Note the $$watchers here:
Without scope: true
With scope: true
The isolated scope has $$watchers == null. So any changes in the scope variable showDialog doesn't fire the watch event. So you might wanna use the parent scope i.e the controller's scope here.
The event fires once as when compiling the directive for the first time it attaches the $watchers to the element only once and for subsequent calls there is no relation between the outer scope to a directive's inner scope.
With that change and few others I have a working plunk.
controller:
myApp.controller('myCtrl', function($scope) {
$scope.showDialog = false;
$scope.toggleModal = function() {
$scope.showDialog = !$scope.showDialog;
};
});
Setting the showDialog to false, whenever the user closes the modal as #Mistalis suggested.
$(element).bind('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
scope.showDialog = false;
});
});
directive:
myApp.directive('modal', function() {
return {
restrict: 'E',
transclude: true,
replace: true,
templateUrl: 'modal-partial.html',
//scope: true,
link: function postLink(scope, element, attrs) {
scope.showModal = function(visible, elem) {
if (!elem)
elem = element;
if (visible)
$(elem).modal("show");
else
$(elem).modal("hide");
}
scope.title = attrs.title;
scope.$watch(attrs.visible, function(value) {
if (value === true)
$(element).modal('show');
else
$(element).modal('hide');
});
$(element).bind('shown.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = true;
});
});
$(element).bind('hidden.bs.modal', function() {
scope.$apply(function() {
scope.$parent[attrs.visible] = false;
scope.showDialog = false;
});
});
}
};
});

how to add dynamic element(template) in angular

Template append content dynamically with value and color like below image using angular. Dynamically create DOM element from back end value with predefined templates.
What elements used in angular js?
directive
template
How to sort the directive in angular JS using Jquery ui sortable?
.directive('contentItem',function($compile){
var imageTemplate = '<div class="mypanel mypanel-default portlet" ng-class="{fullscreen : fullscreen}" ng-show="close">'+
'<div class="mypanel-heading">'+
'<div class="mypanel-btn" >'+
'<i class="{{fullscreenicon}}"></i>'+
'<i class="{{minimizeicon}}"></i>'+
'<i class="fa fa-times"></i>'+
'</div>'+
'<h5 class="mypanel-title">Optional Sizes</h5>'+
'</div>'+
'<div class="mypanel-body" ng-show="on">'+
'<div id="area-chart" class="height300">'+
'</div>'+
'</div>'+
'</div>';
var getTemplate = function(contentType) {
var template = '';
switch(contentType) {
case 'image':
template = imageTemplate;
break;
case 'video':
template = imageTemplate;
break;
case 'notes':
template = imageTemplate;
break;
}
return template;
}
var linker = function(scope, element, attrs) {
scope.on = true;
scope.tooltipminimize = 'Minimize';
scope.minimizeicon = 'fa fa-minus';
scope.fullscreenicon = 'fa fa-expand';
scope.tooltipfullscreen = 'Fullscreen';
scope.fullscreen = false;
scope.close = true;
scope.toggle = function () {
scope.on = !scope.on;
if(scope.tooltipminimize == 'Minimize'){
scope.minimizeicon = 'fa fa-plus';
scope.tooltipminimize = 'Maximize';
}
else{
scope.tooltipminimize = 'Minimize';
scope.minimizeicon = 'fa fa-minus';
}
};
scope.toggleHide = function () {
scope.close = !scope.close;
};
scope.toggleFullscreen = function(){
scope.fullscreen = !scope.fullscreen;
if(scope.tooltipfullscreen == 'Fullscreen'){
scope.fullscreenicon = 'fa fa-compress';
scope.tooltipfullscreen = 'Exit Fullscreen';
}
else{
scope.fullscreenicon = 'fa fa-expand';
scope.tooltipfullscreen = 'Fullscreen';
}
};
scope.sortableOptions = {
connectWith: '.sortable',
item: '.portlet',
placeholder: 'placeholder',
dropOnEmpty: true
};
scope.rootDirectory = 'images/';
element.html(getTemplate('image')).show();
$compile(element.contents())(scope);
}
return{
restrict: "E",
link: linker,
scope:true
};
});
This is definitely a case for a directive. Pass in your arguments, and use the link function to basically build up the template from strings. In the example below, I'm taking parameters to build up inputs for a form.
.directive('qrunChild', ['$compile', function ($compile) {
return {
restrict: 'AE',
require: 'ngModel',
scope: {
ngModel: '=',
},
link: function (scope, element, iAttrs, ngModelController) {
var tpl = '';
var bpstart = '<div class="row no-margin">';
var bp = ' <span class="pull-left"><i class="fa fa-circle text-xs text-info-lt m-r-xs pull-left"></i>{{ngModel.name}}</span><span class="badge pull-right">{{ngModel.type}}</span>';
var bpend = '</div class="row">';
if (scope.ngModel.type == 'text') {
//tpl = '<input type="text" ng-model="ngModel.type">';
}
else if (scope.ngModel.type == 'mc') {
tpl = '<div ng-repeat="opt in ngModel.options"><label class="ui-checks option"><input type="radio" ng-model="ngModel.optionsSelected" value="{{opt.name}}"><i style="margin-right:20px;"></i>{{opt.name}}</label></div>';
}
view = $compile(bpstart + bp + tpl + bpend)(scope);
return $(element).html(view);
}
};
}])
I could call this as follows in my HTML:
Edit: if you wanted to provide a URL to the template instead, you could do something like this (in this case, it's just taking an argument called item.templateUrl in the parent scope):
.directive('dynamicTemplate', function () {
return {
template: '<ng-include src="getTemplateUrl()"/>',
scope: false,
transclude: true,
restrict: 'E',
controller: function ($scope) {
$scope.getTemplateUrl = function () {
//resolve the template
return $scope.item.templateUrl;
}
}
};
})

Angularjs autocomplete in already created directives

I already have a directive for inputbox. i need to implement Autocomplete feature on that
here is my directive code
app.directive("bhAddCategory", ["$rootScope", "$timeout",function($rootScope, $timeout) {
return {
scope: {
rmText: '=bhRmText'
},
replace: true,
template: '<div>' +
'<div class="pull-left forDrop"><input type="text" focus-on="focusMe" ng-class="myColonyList" class="effect1" placeholder="Add a colony" data-ng-model="newCategoryName" data-ng-trim="true" ng-keypress="pressEnter($event)"></div>' +
'<div class="pull-right"><img src="/images/greyplus.png" ng-class="{imageoverflow: imageOverflow}" ng-show="loadplus" data-ng-click="addCategory()" alt="add category"><img src="/images/loader.gif" ng-class="{imageoverflow: imageOverflow}" alt="" ng-show="loadgif" class="colonyloder"></div >' +
'</div>',
link: function(scope, element, attrs) {
scope.loadplus = true;
scope.pressEnter = function(keyEvent) {
if (keyEvent.which === 13)
scope.addCategory();
};
scope.resetNewCategoryName = function() {
if (scope.rmText) {
scope.newCategoryName = '';
}
};
}
};
}]);
How can i implement Auto complete here.
Any Suggestions
Thanks

How to focus on a templates input field on replace in angularjs

node.js and angularjs noob here, so be gentle :).
I am using meanjs for my stack.
I have setup a click to edit function using template replace to add an input field, but I can't work out how to set focus to the input field once automatically when the template changes. My directive looks like this:
angular.module('core').directive("clickToEdit", function(){
var editorTemplate = '<div class="click-to-edit">' +
'<div data-ng-click="enableEditor()" data-ng-hide="view.editorEnabled">' +
'{{value}} ' +
'</div>' +
'<div data-ng-show="view.editorEnabled">' +
'<input data-ng-model="view.editableValue" data-ng-blur="disableEditor()" />' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
You can use focus() function for element like in simple JS. One trick: I wrapped it in $timeout to let template render.
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
</head>
<body ng-app="plunker" ng-controller="MainCtrl">
<div click-to-edit="value"></div>
</body>
<script>
var app = angular.module('plunker', []);
app.controller('MainCtrl', ['$scope', function($scope) {
$scope.value="Click to edit";
}]).directive("clickToEdit", function(){
var editorTemplate = '<div class="click-to-edit">' +
'<div data-ng-click="enableEditor()" data-ng-hide="view.editorEnabled">' +
'{{value}} ' +
'</div>' +
'<div data-ng-show="view.editorEnabled">' +
'<input data-ng-model="view.editableValue" data-ng-blur="disableEditor()" />' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope, $element, $timeout) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
var input = $element.find('input');
$timeout(function() {
input[0].focus();
});
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
</script>
</html>

How to pass multiple attribute in AngularJS directive

How to pass multiple attribute to a directive.
How to pass value 12 of click-to-edit1 inside below div like
<div click-to-edit="location.state" click-to-edit1=12></div>
and should be accessible in directive controller.please help me out.
Code:
App HTML:
<div ng-controller="LocationFormCtrl">
<h2>Editors</h2>
<div class="field">
<strong>State:</strong>
<div click-to-edit="location.state"></div>
</div>
<h2>Values</h2>
<p><strong>State:</strong> {{location.state}}</p>
</div>
App directive:
app = angular.module("formDemo", []);
app.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
'{{value}} ' +
'<a ng-click="enableEditor()">Edit</a>' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue">' +
'Save' +
' or ' +
'<a ng-click="disableEditor()">cancel</a>.' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
App controller:
app.controller("LocationFormCtrl", function($scope) {
$scope.location = {
state: "California",
};
});
Add new property inside directives scope:
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
$scope.location = {
state: "California",
};
});
app.directive("clickToEdit", function() {
var editorTemplate = '<div class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
' {{value}} ' +
'<a ng-click="enableEditor()">Edit</a>' +
'</div>' +
'<div>{{value1}}</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="view.editableValue">' +
'Save' +
' or ' +
'<a ng-click="disableEditor()">cancel</a>.' +
'</div>' +
'</div>';
return {
restrict: "A",
replace: true,
template: editorTemplate,
scope: {
value: "=clickToEdit",
value1: "=clickToEdit1"
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
}
};
});
html:
<div class="field">
<strong>State:</strong>
<div click-to-edit="location.state" click-to-edit1="12"></div>
</div>
working example: http://plnkr.co/edit/e7oTtZNvLdu6w5dgFtfe?p=preview
you first tell the div that you want your directive on it.
<div click-to-edit value='location.state' value1='12'></div>
app.directive("clickToEdit", function() {
return {
restrict: "A",
scope : {
value : "=",
value1 : "="
},
link : function($scope) {
console.log("the first value, should be location.state value on the controller", $scope.value);
console.log("the second value, should be '12'", $scope.value);
}
}
it might seem more logic when you use the directive as a element.
but bottom line is that the diretive looks for attributes on the element, which you then can attach to the directive via the scope. '=' for two way binding, '#' for one way.

Resources