I am trying to use ckeditor with angularjs I have added a directive for the same. It is working fine. The problem is when I try to get the instances list of the ckeditor.
// directive
app.directive('ckeditor', function () {
return {
require: '?ngModel',
link: function (scope, element, attr, ngModel) {
var ck = CKEDITOR.replace(element[0]);
if(!ngModel)return;
ck.on('pasteState', function () {
scope.$apply(function () {
ngModel.$setViewValue(ck.getData());
});
});
ngModel.$render = function (value) {
ck.setData(ngModel.$viewValue);
};
}
};
});
// ng-repeat
<div ng-repeat="key in []| range:0:(vm.listCount-1)">
<textarea ckeditor id="content_{{key + 1}}"
ng-model="vm.contentList[key].content">
</textarea>
</div>
In controller I am trying to get instances list. There instead of
content_0,content_1 etc. I am getting content_{{key + 1}} only one instance
console.log(CKEDITOR.instances);
I want to get the proper instance of the ckeditor but I am getting only one value that is content_{{key + 1}} Please someone suggest.
My guess is that the directive needs to set the id attribute before invoking CKEDITOR.replace:
app.directive('ckeditor', function () {
return {
require: '?ngModel',
link: function (scope, element, attr, ngModel) {
//COMPUTE id attribute
if (attr.key) {
var keyValue = scope.$eval(attr.key);
element[0].id += "_"+keyValue;
};
var ck = CKEDITOR.replace(element[0]);
if(!ngModel)return;
ck.on('pasteState', function () {
scope.$apply(function () {
ngModel.$setViewValue(ck.getData());
});
});
ngModel.$render = function (value) {
ck.setData(ngModel.$viewValue);
};
}
};
});
Usage:
<div ng-repeat="key in [0,1]">
<textarea ckeditor key="$index+1" id="content"
ng-model="vm.contentList[key].content">
</textarea>
</div>
The CKEDITOR is likely instantiating the editor before the AngularJS framework computes id="content_{{key + 1}}".
Related
I have ckeditor with wiris plug in ,and I have ck-editors instances in ng-repeate ,when user posts any wiris question at any instance of ck-editor ,that post is posted to fist instance of ck-editor.I want if 3 instances of ck-editors in ng-repeat,users post 2nd instance of ck-editor with wiris equation then that post should show at only 2nd instance of ck-editor only ,Presently it shows at only 1st instance .
My html :
<div ng-repeat="item in items">
<form role="form" name="DiscussionForm" novalidate>
<input type="text" name="followup" ng-model="followupDis"
ck-editor placeholder="Compose" required>
<div><button type="submit"ng-click="start()">Post</button>
</div>
</form>
</div>
in js
app.directive('ckEditor', function() {
return {
require: '?ngModel',
link: function(scope, elm, attr, ngModel) {
var ck = CKEDITOR.replace(elm[0]);
if (!ngModel) return;
ck.on('instanceReady', function() {
ck.setData(ngModel.$viewValue);
});
function updateModel() {
scope.$apply(function() {
ngModel.$setViewValue(ck.getData());
});
}
ck.on('change', updateModel);
ck.on('focus', updateModel);
ck.on('key', updateModel);
ck.on('dataReady', updateModel);
ngModel.$render = function(value) {
ck.setData(ngModel.$viewValue);
};
}
};
});
I am expecting in directive I have create the instance for the first element var ck = CKEDITOR.replace(elm[0]); so it should change.
So any one can share the solution for multiple instances of ckeditor with wiris .
I have found by changing the id of the attribute we can solve this one .
in js:
app.directive('ckEditor', function() {
var counter = 0, prefix = "followupDiscussionPostReply-";
return {
require: '?ngModel',
link: function(scope, elm, attr, ngModel) {
if (!attr.id) {
attr.$set('id', prefix + (++counter));
}
// rest of the code
these changes fixed the multiple ckeditors have same ngModel issue for me .
I have a controller function and I cannot call it inside the directive. I am trying hard. is there any thing Else i am failing to do? please tell me. I have included my code here. I have searched many places followed many answers and now I am stuck at this
(function () {
var app = angular.module("featureModule", ['ngRoute']);
//
app.directive('myGoogleAutocomplete', function () {
return {
replace: true,
require: 'ngModel',
scope: {
ngModel: '=',
googleModel: '=',
onSelect: '&?', // optional callback on selected successfully: 'onPostedBid(googleModel)'
},
template: '<input class="form-control" type="text" style="z-index: 100000;" autocomplete="on">',
link: function ($scope, element, attrs, model)
{
var autocomplete = new google.maps.places.Autocomplete(element[0], googleOptions);
google.maps.event.addListener(autocomplete, 'place_changed', function () {
$scope.$apply(function () {
var place = autocomplete.getPlace();
if (!place.geometry)
{
// User entered the name of a Place that was not suggested and pressed the Enter key, or the Place Details request failed.
model.$setValidity('place', false);
//console.log("No details available for input: '" + place.name + "'");
return;
}
$scope.googleModel = {};
$scope.googleModel.placeId = place.place_id;
$scope.googleModel.latitude = place.geometry.location.lat();
$scope.googleModel.longitude = place.geometry.location.lng();
$scope.googleModel.formattedAddress = place.formatted_address;
if (place.address_components) {
$scope.googleModel.address = [
$scope.extract(place.address_components, 'route'),
$scope.extract(place.address_components, 'street_number')
].join(' ');
}
model.$setViewValue(element.val());
model.$setValidity('place', true);
if (attrs.onSelect)
{
//how to call controller function here?
$scope.onSelect({ $item: $scope.googleModel });
}
});
});
}
}
});
app.controller("featureController", function($scope,$http,$rootScope,close,ModalService,NgMap) {
console.log($rootScope.permService);
$scope.onSelect=function(val)
{
console.log(val);
}
});
<my-google-autocomplete id="address" name="address" ng-model="task.house_no" google-model="model.googleAddress"
on-select="vm.onSelectGoogleAddress($item)" autocomplete="off" required>
</my-google-autocomplete>
There is no onSelectGoogleAddress() function in the controller. I see only onSelect() function. Change on-select value passed in the html.
<my-google-autocomplete id="address" name="address" ng-model="task.house_no" google-model="model.googleAddress"
on-select="onSelect($item)" autocomplete="off" required>
</my-google-autocomplete>
You can bind callback event by using elemet inside link function.
Here is the example . Hope it helps.
Let the controller having callback function from directive as below
app.controller('MainCtrl', function($scope) {
$scope.SayHello=function(id){
alert(id);
}
});
Let the directive
app.directive('dirDemo', function () {
return {
scope: {
okCallback: '&'
},
template: '<input type="button" value="Click me" >',
link: function (scope, element, attrs) {
var param='from directive';
element.bind('click', function () {
scope.$apply(function () {
scope.okCallback({id:param});
});
});
}
}
});
HTML is
<body ng-controller="MainCtrl">
<div dir-demo
ok-callback="SayHello(id)"
</div>
</body>
Working plunker https://plnkr.co/edit/RbFjFfqR1MDDa3Jwe8Gq?p=preview
I am using the following code to get the "auto tab" working with AngularJS (automatically tabs the user to the "Title" textbox after the max length is met for the "Name" textbox):
var app = angular.module('plunker', []);
app.directive('autoTabTo', [function () {
return {
restrict: "A",
link: function (scope, el, attrs) {
el.bind('keyup', function(e) {
if (this.value.length === this.maxLength) {
var element = document.getElementById(attrs.autoTabTo);
if (element)
element.focus();
}
});
}
}
}]);
Here is my HTML (with my custom directives):
<customtextfield autoTabTo="Variant.Specs.Title" ng-maxlength="20" customfield="Variant.Specs.Name"></customtextfield>
<customtextfield ng-maxlength="25" customfield="Variant.Specs.Title"></customtextfield>
Would you happen to know what I am doing wrong?
This piece of code should do it. Let's keep it as simple as possible. :)
HTML:
<div ng-app="autofocus">
<label>Name:</label>
<input ng-model="maxLengthReach"></input>
<br/><br/>
<label>Title:</label>
<input autofocus-when></input>
</div>
Javascript:
var app = angular.module('autofocus', []);
app.directive('autofocusWhen', function () {
return function (scope, element, attrs) {
scope.$watch('maxLengthReach', function(newValue){
if (newValue.length >= 5 ) {
element[0].focus();
}
});
}
});
jsFiddle: http://jsfiddle.net/gctvyfcz/1/
Your first error is your markup is wrong for using the directive. Should be
<input auto-tab-to="Variant.Specs.Title" ng-maxlength="4" customfield="Variant.Specs.Name"></input>
Directive should be changed to:
app.directive('autoTabTo', [function () {
return {
restrict: "A",
link: function (scope, el, attrs) {
el.bind('keyup', function(e) {
if (this.value.length === parseInt(attrs.ngMaxlength)) {
var element = document.getElementById(attrs.autoTabTo);
if (element)
element.focus();
}
});
}
}
}]);
Also, you don't have an ID on your second element so it won't find it:
<input ng-maxlength="4" customfield="Variant.Specs.Title" id="Variant.Specs.Title"></input>
working plunker
I'm new to AngularJs and learning now, in my current assignment I need to achieve multiple things on ng-click.
To hide and show some DOM elements based on the ng-click
Change the background of the element where the ng-click is applied on, I'm trying to acheive this using a directive.
Mark-up:
<div class="catFilter f6" ng-click="showSubCat = !showSubCat;toggleDropDown()">
Choose A Genre
</div>
<div class="inactive" ng-show="showSubCat" ng-click="hideSubCat = !hideSubCat" ng-hide="!hideSubCat">
</div>
<div class="cat-drop-menu-list" ng-show="showSubCat" ng-hide="!hideSubCat">
</div>
angular directive
retailApp.directive('toggleDropDown', function() {
return function(scope, element, attrs) {
$scope.clickingCallback = function() {
element.css({'background':'url("../images/down-arrow.png") no-repeat 225px 12px;'});
};
element.bind('click', $scope.clickingCallback);
}
});
Issues:
I'm not able to see the directive being applied, i.e., when I click on choose a genre, it is hiding and showing the other two divs, but not changing the back ground.
You can do this a couple ways, with bindings or directives:
http://jsfiddle.net/abjeex75/
var app = angular.module('app', []);
app.controller('AppCtrl', function ($scope) {
$scope.show_sub_cat = false;
$scope.show = function () {
$scope.show_sub_cat = true;
}
$scope.hide = function () {
$scope.show_sub_cat = false;
}
});
app.directive('toggleBg', function () {
var directive = {
restrict: 'A',
link: link
}
return directive;
function link(scope, element, attr) {
element.on('click', function () {
element.toggleClass('red');
});
}
});
I have places in my code where I have this:
<input data-ng-disabled="SOME_SCOPE_VARIABLE" />
I would like to be able to use it like this too:
<input data-ng-autofocus="SOME_SCOPE_VARIABLE" />
Or even better, mimicking how ng-style is done:
<input data-ng-attribute="{autofocus: SOME_SCOPE_VARIABLE}" />
Does this exist in the current version of AngularJS? I noticed in the code there's a BOOLEAN_ATTR which gets all the attr's that AngularJS supports. I don't want to modify that in fear of changing versions and forgetting to update.
Update: AngularJS now has an ngFocus directive that evaluates an expression on focus, but I mention it here for the sake of completeness.
The current version of AngularJS doesn't have a focus directive, but it's in the roadmap. Coincidentally, we were talking about this on the mailing list yesterday, and I came up with this:
angular.module('ng').directive('ngFocus', function($timeout) {
return {
link: function ( scope, element, attrs ) {
scope.$watch( attrs.ngFocus, function ( val ) {
if ( angular.isDefined( val ) && val ) {
$timeout( function () { element[0].focus(); } );
}
}, true);
element.bind('blur', function () {
if ( angular.isDefined( attrs.ngFocusLost ) ) {
scope.$apply( attrs.ngFocusLost );
}
});
}
};
});
Which works off a scope variable as you requested:
<input type="text" ng-focus="isFocused" ng-focus-lost="loseFocus()">
Here's a fiddle: http://jsfiddle.net/ANfJZ/39/
You can do this with the built-in ngAttr attribute bindings.
<input ng-attr-autofocus="{{SOME_SCOPE_VARIABLE}}">
The autofocus attribute will be added if SOME_SCOPE_VARIABLE is defined (even if it's false), and will be removed if it's undefined. So I force falsy values to be undefined.
$scope.SOME_SCOPE_VARIABLE = someVar || undefined;
This directive should do the trick:
angular.module('utils.autofocus', [])
.directive('autofocus', ['$timeout', function($timeout) {
return {
restrict: 'A',
scope: {'autofocus':'='}
link : function($scope, $element) {
$scope.$watch 'autofocus', function(focus){
if(focus){
$timeout(function() {
$element[0].focus();
});
}
}
}
}
}]);
Taken from here: https://gist.github.com/mlynch/dd407b93ed288d499778
scope.doFocus = function () {
$timeout(function () {
document.getElementById('you_input_id').focus();
});
};
Create a directive like this
.directive('autoFocus', ['$timeout', function ($timeout) {
return {
restrict: 'A',
link: function ($scope, $element) {
$timeout(function () {
$element[0].focus();
});
}
}
<input type="text" auto-focus class="form-control msd-elastic" placeholder="">
What I did is using regular autofocus on my inputs: <input autofocus>
And then I set the focus on the first visible input with autofocus when angular is ready:
angular.element(document).ready(function() {
$('input[autofocus]:visible:first').focus();
});
Hope this helps.
I did it with two custom directives, something like this:
(function(angular) {
'use strict';
/* #ngInject */
function myAutoFocus($timeout) {
return {
restrict: 'A',
link: function(scope, element) {
$timeout(function() {
element[0].focus();
}, 300);
}
};
}
function myFocusable() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var focusMethodName = attrs.myFocusable;
scope[focusMethodName] = function() {
element[0].focus();
};
}
};
}
angular
.module('myFocusUtils', [])
.directive('myAutoFocus', myAutoFocus)
.directive('myFocusable', myFocusable);
}(angular));
If you add attribute my-auto-focus to an element, it will receive focus after 300ms. I set the value to 300 instead of 0 to let other async components to load before setting the focus.
The attribute my-focusable will create a function in the current scope. This function will set focus to the element when called. As it creates something in the scope, be cautious to avoid overriding something.
This way you don't need to add something to Angular's digest cycle (watch) and can do it entirely in the view:
<input my-focusable="focusOnInput"></input>
<button ng-click="focusOnInput()">Click to focus</button>
I created a JSFiddle to show the myFocusable directive: http://jsfiddle.net/8shLj3jc/
For some reason I don't know, the myAutoFocus directive does not work in JSFiddle, but it works in my page.
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="namesCtrl">
<div ng-repeat="x in names">
<input ng-attr-focus={{$first}} value="{{x.name + ', ' + x.country }}" />
</div>
</div>
<script>
var myApp = angular.module('myApp', []);
myApp.controller('namesCtrl', function($scope) {
$scope.names = [
{name:'x1',country:'y1'},
{name:'x2',country:'y2'},
{name:'x3',country:'y3'}
];
});
myApp.directive("focus", function(){
return {
restrict: "A",
link: function link(scope, element, attrs) {
if(JSON.parse(attrs.focus)){
element[0].focus();
}
}
};
});
</script>
</body>
</html>
had created above custom directive for one of my use case.
always focusses on first input element.
works for ajax data, browser back/forward buttons.
Tested on chrome and firefox(default autofocus is not supported here)
JSON.parse is used to parse string "true" returned from html to boolean true in JS.
another way to use attrs.focus === "true" for if condition.
so without $timeout you can also use auto focus like this -
<input type="text" ng-show="{{condition}}" class='input-class'></input>
angular.element(document).ready(function(){
angular.element('.input-class')[0].focus();
});
Combining whar others mentioned above:
JS Code:
myApp.directive('ngAutofocus', ['$timeout', function ($timeout) {
var linker = function ($scope, element, attrs) {
$scope.$watch('pageLoaded', function (pageLoaded) {
if (pageLoaded) {
$timeout(function () {
element[0].focus();
});
}
});
};
return {
restrict: 'A',
link: linker
};
}]);
HTML:
<input type="text" ng-model="myField" class="input-block-level edit-item" ng-autofocus>
Set pageLoaded to true from your initial load method of the page get:
var loadData = function () {
..
return $http.get(url).then(function (requestResponse) {
$scope.pageLoaded = true;
......
}