How to focus on a templates input field on replace in angularjs - 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>

Related

Error: [$compile:ctreq] data passing between two directive from different module

I have two different module in which I have two directives. I need to pass data between these two directive. I use require property. but I get some error
Error: [$compile:ctreq] Controller 'yearSort', required by directive 'budgetSort', can't be found!
My first directive is
angular.module('movieApp.yearsort.directives', []).directive('yearSort',[function(){
return{
restrict : 'AEC',
replace : true,
transclude : true,
controller : 'YearsortController',
templateUrl : 'app/components/yearsort/yearsort.html',
};
}]);
In the YearsortController I have the code
angular.module('movieApp.yearsort.controller', []).controller('YearsortController', ['$scope','HomeFactory','$timeout','$state',function($scope,HomeFactory,$timeout,$state) {
this.sayHello = function() {
$scope.words = "my requier";
console.log( $scope.words);
};
}]);
In my second directive I have the code
angular.module('movieApp.budgetsort.directives', []).directive('budgetSort',[function(){
return{
restrict : 'AEC',
replace : true,
transclude : true,
controller : 'BudgetsortController',
templateUrl : 'app/components/budgetSort/budgetSort.html',
require : "yearSort",
link : function(scope,element, attrs, demoCtrl){
demoCtrl.sayHello();
}
};
}]);
Why don't you try using a Service/Factory? It is a good option when you need to pass data through components or directives
I've made this plunkr to explain: http://plnkr.co/edit/V7BLbOrrtNhXl1QlUKxA?p=preview
HTML:
<body ng-controller="myCtrl">
<first-directive></first-directive>
<second-directive></second-directive>
</body>
Javascript:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, dataService) {
$scope.name = 'World';
//set up the items.
angular.copy([ { name: 'test'} , { name: 'foo' } ], dataService.items);
});
app.directive('firstDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 1</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.directive('secondDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 2</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.factory('dataService', [function(){
return { items: [] };
}]);
The Demo
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope, dataService) {
$scope.name = 'World';
//set up the items.
angular.copy([ { name: 'test'} , { name: 'foo' } ], dataService.items);
});
app.directive('firstDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 1</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.directive('secondDirective', function(dataService){
return {
restrict: 'E',
template: '<h3>Directive 2</h3>' +
'<div ng-repeat="item in data.items">' +
'<input type="text" ng-model="item.name"/>' +
'</div>',
link: function(scope, elem, attr) {
scope.data = dataService;
}
};
});
app.factory('dataService', [function(){
return { items: [] };
}]);
<script src="//unpkg.com/angular/angular.js"></script>
<body ng-app="myApp" ng-controller="myCtrl">
<first-directive></first-directive>
<second-directive></second-directive>
</body>

AngularJS ng-click doesn't fire

I generate some a Tags dynamically from a json file and add them like this to the page:
for(var i = 0; i < currentScene.hotpoints.hotpoint.length; i++)
{
var hotpoint = currentScene.hotpoints.hotpoint[i];
var pos = hotpoint.pos.split(";");
var x = parseFloat(pos[0]) * multiplierX;
var y = parseFloat(pos[1]) * multiplierY;
htmlstring += '<a href ng-controller="main" id="hp'+ hotpoint.ID + '" class="hotpoint animated infinite" style="top: ' + parseInt(y) + 'px; left: ' + parseInt(x) + 'px;" ng-click="enterScene(' +hotpoint.sceneID + ',' + hotpoint.ID +')"></a>';
}
$scope.hotpoints = $sce.trustAsHtml(htmlstring);
That works great. Now like you see I want to enable the click event for each element. So I use ng-click. But it doesn't get fired.
When I add this ng-click to an "static" element which is already on the site everything works.
What I have to care about that this works?
Thanks
Yes... $compile shall be used for this..
(function(){
"use strict";
angular.module("CompileDirective", [])
.directive('dynamicElement', ['$compile', function ($compile) {
return {
restrict: 'E',
scope: {
message: "="
},
replace: true,
link: function(scope, element, attrs) {
var template = $compile(scope.message)(scope);
element.replaceWith(template);
},
controller: ['$scope', function($scope) {
$scope.clickMe = function(){
alert("hi")
};
}]
}
}])
.controller("DemoController", ["$scope", function($scope){
$scope.htmlString = '<div><input type="button" ng-click="clickMe()" value="click me!"/> </div>';
}])
}());
With the following HTML:
<div ng-controller="DemoController">
<dynamic-element message='htmlString'></dynamic-element>
</div>
OR you may also go for injecting $compile in controller..
app.controller('AppController', function ($scope, $compile) {
var $el = $('<td contenteditable><input type="text" class="editBox" value=""/></td>' +
'<td contenteditable><input type="text" class="editBox" value=""/></td>' +
'<td>' +
'<span>' +
'<button id="createHost" class="btn btn-mini btn-success" data-ng-click="create()"><b>Create</b></button>' +
'</span>' +
'</td>').appendTo('#newTransaction');
$compile($el)($scope);
$scope.create = function(){
console.log('clicked')
}
})
And the easiest way..
$("#dynamicContent").html(
$compile(
"<button ng-click='count = count + 1' ng-init='count=0'>Increment</button><span>count: {{count}} </span>"
)(scope)
);

Set focus of text box in directive

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();
})
}

angular directive scope inheritance/ isolation

I have a directive to build dynamic table from a collection. It have two types of columns checkbox and dropdowns. However, the scope is not resolving correctly at directive level. They are getting as 'undefined'. Also I need to bind drop down options from the controller.
html
<div ng-app="myApp">
<div ng-controller="MyCtrl">
<ui-table source="students">
<check-col title="passed" field="passed"/>
<drop-down-col title="std" field="std" />
</ui-table>
</div>
</div>
Angular js
var myApp = angular.module('myApp',[]);
myApp.directive("uiTable", function ($compile) {
var generateTableHtml = function ($scope) {
// header
var html = "<table class='table table-condensed table-bordered table-responsive'><thead class='thead12'><tr class='active'>";
angular.forEach($scope.columns, function (col) {
debugger;
html += "<th scope='col'" +
(col.cssClass ? " class='" + col.cssClass + "'" : "") +
">" + col.title + "</th>";
});
html += "</tr></thead><tbody>";
// body
html += "<tr ng-repeat='item in dataSource'>";
angular.forEach($scope.columns, function (col) {
html += "<td" + (col.cssClass ? " class='" + col.cssClass + "'" : "") + ">";
if (col.type === ColumnType.Check) {
html += "<input type='checkbox' ng-model='item." + col.dataField + "'/>";
} else if (col.type === ColumnType.DropDown) {
html += "<select ng-model='item." +col.dataField + "' ng-options = 'option.Value for option in dataOptions'></select>";
}
html += "</td>";
});
html += "</tr>";
html += "</tbody></table>";
return html;
};
return {
restrict: "E",
replace: true,
transclude: true,
scope: {
dataSource: "=source"
},
controller: function ($scope) {
$scope.columns = [];
this.addColumn = function (col) {
$scope.columns.splice(0, 0, col);
};
},
template: "<div ng-transclude></div>",
compile: function () {
return function ($scope, $elem) {
$elem.html(generateTableHtml($scope));
$compile($elem.contents())($scope);
};
}
};
});
myApp.directive("checkCol", function () {
return {
require: "^uiTable",
restrict: "E",
replace: true,
scope: {
title: "#title",
cssClass: "#class",
dataField: "#field"
},
link: function ($scope, element, attrs, tableControl) {
$scope.type = ColumnType.Check;
tableControl.addColumn($scope);
}
};
});
myApp.directive("dropDownCol", function() {
return {
require: "^uiTable",
restrict: "E",
replace: true,
scope: {
title: "#title",
cssClass: "#class",
dataField: "#field"
},
link: function($scope, element, attrs, tableControl) {
$scope.type = ColumnType.DropDown;
tableControl.addColumn($scope);
}
};
});
//myApp.factory('myService', function() {});
var ColumnType = { Check: 1, DropDown: 2 };
myApp.controller('MyCtrl', function($scope) {
$scope.students = [{id:1, std:10, passed: true}, {id:2, std:9, passed: false}];
$scope.stds= [{Value: 10, Name: '10the std'},{Value: 9, Name: '9the std'},{Value: 8, Name: '8the std'}];
});
JSFIDDLE
Uprade the angular ver. to 1.2 and it works fine
`http://jsfiddle.net/HB7LU/18635/`

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