I have tried using k-content-editable and well as just the generic data-ng-disabled but neither of these worked. Looking at the documentation it's not even clear to me there is a way to disable the control.
You can do this by creating a custom directive:
.directive("kNgDisabled", function() {
return {
restrict: "A",
link: function(scope, element, attr) {
scope.$on("kendoWidgetCreated", function(e, widget) {
var value = scope.$eval(attr.kNgDisabled);
$(widget.body).attr("contenteditable", !value);
scope.$watch(attr.kNgDisabled, function(value) {
$(widget.body).attr("contenteditable", !value);
});
})
}
}
});
Then use it like this:
<textarea kendo-editor k-ng-disabled="disabled"></textarea>
Here is a live demo: http://dojo.telerik.com/#korchev/AdApu
Add following code in your Angular controller->
var x = document.getElementById("myForm");
x.addEventListener("focus", myFocusFunction, true);
function myFocusFunction() {
$($('#keFinding').data().kendoEditor.body).attr('contenteditable', false);
}
Related
I'm trying to write a directive for HighCharts in AngularJS which supports two way data binding as well as click events on charts.
Directive:
app.directive('highchart', function () {
return {
restrict: 'E',
template: '<div></div>',
replace: true,
link: function (scope, element, attrs) {
scope.$watch(scope.example_chart, function() {
var chart = JSON.parse(attrs.chart)
element.highcharts(chart);
}
}
}
});
Now, when I write my HTML like this:
<div>
<highchart chart='example_chart'></highchart>
</div>
It supports the click event, but not two way data binding.
And, when it is passed as an expression:
<div>
<highchart chart='{{example_chart}}'></highchart>
</div>
It supports two way data binding but the function written in JSON of example_chart for click event doesn't get parsed and hence not functioning.
So, suggest a way to handle both the cases in AngularJS way.
highcharts-ng
You can use highcharts-ng directive, See usage here: Fiddle
Also you can use custom directive:
Custom
See demo in Fiddle
Actually there is nothing special here, pretty simple isolate scope directive with watcher on highChart configuration (defined as JSON).
I my case I used several watchers on specific fields to improve perforamnce but you can run deep watch on all config object
HTML
<high-chart config="chartConfig"> </high-chart>
JS
myapp.directive('highChart',
function () {
return {
restrict: 'E',
replace:true,
scope: {
config: '='
},
template: '<div id="container" style="min-width: 310px; height: 400px; margin: 0 auto"></div>',
link: function (scope, element, attrs) {
var chart = false;
var initChart = function() {
if (chart) chart.destroy();
var config = scope.config || {};
//var mergedOptions = getMergedOptions(scope, element, config);
chart = new Highcharts.Chart(config);
if(config.loading) {
chart.showLoading();
}
};
initChart();
scope.$watch('config.loadRandomData', function (value) {
if(value == false){return;}
chart.series[0].setData(scope.config.series[0].data);
scope.config.loadRandomData = false;
}, true);
scope.$watch('config.loading', function (loading) {
if(loading) {
chart.showLoading();
} else {
chart.hideLoading();
}
});
scope.$watch('config.series[0].type', function (type) {
chart.series[0].update({type: type});
});
scope.$watch('config.series[0].dataLabels.enabled', function (enableDataLabels) {
chart.series[0].update({dataLabels: {enabled: enableDataLabels}});
});
}//end watch
}
}) ;
I am writing and AngularJS directive for DagreD3. I have some problems with $scope update in Angular. When I update the Model, the Directive does not re-render the graph.
A plunker can be found here.
My directive looks like this:
myApp.directive('acDagre', function() {
function link(scope, element, attrs) {
scope.$watch(scope.graph, function(value) {
alert('update'); //NOT EVEN THIS IS CALLED ON UPDATE
});
var renderer = new dagreD3.Renderer();
renderer.run(scope.graph, d3.select("svg g"));
}
return {
restrict: "A",
link: link
};
The variable $scope.graph is modified in the Controller during runtime like this:
$scope.addNode = function(){
$scope.graph.addNode("kbacon2", { label: "Kevin Bacon the second" });
}
Did I understand something wrong in Angular? Everytime the Variable $scope.graph is changed, i want the graph to update.
You can find more information in the Plunker.
Thank you for very much your help!
The watcher should look either like this:
scope.$watch('graph', function(value) {
console.log('update');
});
Or like this:
scope.$watch(function () { return scope.graph; }, function(value) {
console.log('update');
});
It will not fire when adding nodes however, cause it's comparing by reference.
You can add true as a third parameter to perform a deep watch instead (it will use angular.equals):
scope.$watch('graph', function(value) {
console.log('update');
}, true);
Note that this is more expensive.
Example:
.directive('acDagre', function() {
var renderer = new dagreD3.Renderer();
function link(scope, element, attrs) {
scope.$watch(function () { return scope.graph; }, function(value) {
render();
}, true);
var render = function() {
renderer.run(scope.graph, d3.select("svg g"));
};
}
return {
restrict: "A",
link: link
};
});
Demo: http://plnkr.co/edit/Dn1t3sMH58mDz9HhqYD5?p=preview
If you are just changing the nodes you can define the watchExpression like this instead:
scope.$watch(function () { return scope.graph._nodes; }
Deep watching large objects can have a negative effect on performance. This will of course depend on the size and complexity of the watched object and the application, but it's good to be aware of.
Is it possible to apply two way binding to a <textarea></textarea> that has had TinyMCE applied to it for Rich Text Formatting.
I can't get it to work! I can get TinyMCE to load the content of my model, but when I update the text in TinyMCE, my model does not auto update!
Is there a way?
You can do this by creating your own directive.
What you need to do is to let your directive sync your model when something in the TinyMCE editor changes. I have not used TinyMCE, but Wysihtml5. I think you can remake this to use TinyMCE instead.
angular.module('directives').directive('wysihtml5', ['$timeout',
function ($timeout) {
return {
restrict: 'E',
require: 'ngModel',
template: "<textarea></textarea>", // A template you create as a HTML file (use templateURL) or something else...
link: function ($scope, $element, attrs, ngModel) {
// Find the textarea defined in your Template
var textarea = $element.find("textarea");
// When your model changes from the outside, use ngModel.$render to update the value in the textarea
ngModel.$render = function () {
textarea.val(ngModel.$viewValue);
};
// Create the editor itself, use TinyMCE in your case
var editor = new wysihtml5.Editor(textarea[0],
{
stylesheets: ["/style.css"],
parserRules: wysihtml5ParserRules,
toolbar: true,
autoLink: true,
useLineBreaks: false,
});
// Ensure editor is rendered before binding to the change event
$timeout(function () {
// On every change in the editor, get the value from the editor (textarea in case of Wysihtml5)
// and set your model
editor.on('change', function () {
var newValue = textarea.val();
if (!$scope.$$phase) {
$scope.$apply(function () {
ngModel.$setViewValue(newValue);
});
}
});
}, 500);
}
};
}]);
Then you can use the directive in your html page like this:
<wysihtml5 ng-model="model.text" />
Here's a link if you need more info on creating your own directive: http://docs.angularjs.org/guide/directive
Also compare the render function from the directive above to this render function from angular-ui-tinymce ( https://github.com/angular-ui/ui-tinymce )
ngModel.$render = function() {
if (!tinyInstance) {
tinyInstance = tinymce.get(attrs.id);
}
if (tinyInstance) {
tinyInstance.setContent(ngModel.$viewValue || '');
}
Plnkr: http://plnkr.co/edit/04AFkp?p=preview
However depending on the timing of the loading of your DOM you may need to set the priority on your directive upwards. :-)
Here is my solution using a custom angular directive.
You'll need to use jQuery with angularJS, TinyMCE 4 and their jQuery plugin.
myApp.directive('tinymce', function() {
return {
restrict: 'C',
require: 'ngModel',
link: function(scope, element, attrs, modelCtrl) {
element.tinymce({
setup: function (e) {
e.on("change", function() {
modelCtrl.$setViewValue(element.val());
scope.$apply();
}
}
});
}
}
}
Then in your HTML:
<textarea class="tinymce" ng-model="data"></textarea>
That's it, have fun.
It seems everyone is asleep on the angularjs google group :)
Here's my problem:
I have a select in a directive, and I want to bind a function to the 'change' event of that select.
My problem is that when I use this directive in an ng-repeat loop, the bind to the event doesn't work anymore (why ??).
EDIT:
In my real case, there are three or more <select>, created and populated with data from a json file.
Here is a simplified version of the directive, and I made a plunker as well.
angular.module('test', [])
.directive('mySelect', function() {
var baseElt = angular.element('<select><option>1</option><option>2</option></select>');
return {
restrict: 'E',
compile: function(topElement) {
var elt = baseElt.clone();
topElement.append(elt);
return function(scope, element, attributes, ngModelCtrl) {
elt.bind('change', function() {
alert("change !");
});
};
}
};
});
you need
app.directive('mySelect', function() {
return {
restrict : 'E',
template : '<select><option>1</option><option>2</option></select>',
link : function(scope, element, attributes, ngModelCtrl) {
element.bind('change', function() {
console.log("change !");
});
}
}
});
Demo: Fiddle
I'm building an application using AngularJS and UniformJS. I'd like to have a reset button on the view that would reset my select's to their default value. If I use uniform.js, it isn't working.
You can examine it here:
http://plnkr.co/edit/QYZRzlRf1qqAYgi8VbO6?p=preview
If you click the reset button continuously, nothing happens.
If you remove the attribute, therefore no longer using uniform.js, everything behaves correctly.
Thanks
UPDATE:
Required the use of timeout.
app.controller('MainCtrl', function($scope, $timeout) {
$scope.reset = function() {
$scope.test = "";
$timeout(jQuery.uniform.update, 0);
};
});
Found it. For the sake of completeness, I'm copying my comment here:
It looks like Uniform is really hacky. It covers up the actual select element, and displays span instead. Angular is working. The actual select element's value is changing, but the span that Uniform displays is not changing.
So you need to tell Uniform that your values have changed with jQuery.uniform.update. Uniform reads the value from the actual element to place in the span, and angular doesn't update the actual element until after the digest loop, so you need to wait a little bit before calling update:
app.controller('MainCtrl', function($scope, $timeout) {
$scope.reset = function() {
$scope.test = "";
$timeout(jQuery.uniform.update, 0);
};
});
Alternatively, you can put this in your directive:
app.directive('applyUniform',function($timeout){
return {
restrict:'A',
require: 'ngModel',
link: function(scope, element, attr, ngModel) {
element.uniform({useID: false});
scope.$watch(function() {return ngModel.$modelValue}, function() {
$timeout(jQuery.uniform.update, 0);
} );
}
};
});
Just a slightly different take on #john-tseng's answer. I didn't want to apply a new attribute to all my check-boxes as we had quite a few in the application already. This also gives you the option to opt out of applying uniform to certain check-boxes by applying the no-uniform attribute.
/*
* Used to make sure that uniform.js works with angular by calling it's update method when the angular model value updates.
*/
app.directive('input', function ($timeout) {
return {
restrict: 'E',
require: '?ngModel',
link: function (scope, element, attr, ngModel) {
if (attr.type === 'checkbox' && attr.ngModel && attr.noUniform === undefined) {
element.uniform({ useID: false });
scope.$watch(function () { return ngModel.$modelValue }, function () {
$timeout(jQuery.uniform.update, 0);
});
}
}
};
});
Please try blow code.
app.directive('applyUniform', function () {
return {
restrict: 'A',
link: function (scope, element, attrs) {
if (!element.parents(".checker").length) {
element.show().uniform();
// update selected item check mark
setTimeout(function () { $.uniform.update(); }, 300);
}
}
};
});
<input apply-uniform type="checkbox" ng-checked="vm.Message.Followers.indexOf(item.usrID) > -1" ng-click="vm.toggleSelection(item.usrID)" />