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.
Related
I have following directive
var app = angular.module('TestApp', []);
app.directive('selectMultiple', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
$(element).find('select').material_select();
$(element).find("ul li").first().click(function() {
$(element).find("ul li:not(:first-child)").each(function(index) {
$(this).find("input[type=checkbox]").prop("checked", $(element).find("ul li").first().find("input[type=checkbox]").prop("checked"));
});
});
}
};
});
And I am also using dirpagination on same page, Its working , but when page changed, means DOM gets new elements, whatever written in directive is completely not working.
AM I missing any thing, I am new to angular so might be I'll be missing some things
Thanks
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);
}
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
}
}) ;
Just changed to Angular 1.2.0-rc.3 (from 1.2.0-rc.2) and directive for inline Editor doesn't work anymore.
Works fine in normal mode but not inline.
Does anyone knows how to fix this?
Thanks.
app.directive('uiCkeditor', [function() {
return {
require: '?ngModel',
link: function(scope, element, attrs, ngModel) {
if (!ngModel)
return;
ngModel.$render = function(value) {
ck.setData(ngModel.$viewValue);
}
// var ck = CKEDITOR.replace(element[0]);
var ck = CKEDITOR.inline(element[0])
ck.on('pasteState', function() {
ngModel.$setViewValue(ck.getData());
scope.$apply();
});
}
}
}])
I used ng-bind-html to render what is in the model and I created the directive ck-inline to add the inline feature and bind the model to the changes that happen in the inline editor. This directive requires a ng-bind-html to work and you also need to have ngSanitize added to your module. Add directive ck-inline to your element and it should work fine.
I would recommend you to use a different directive for the regular editor since it has a different behavior and can work well enough with just the ng-model directive.
I also use $timeout because I noticed that if I don't the text is rendered and then ckeditor somehow deletes all the values which messes up the model (this does not happen with the non-inline option). Here is the code.
yourModule.directive('ckInline', ['$sce', '$timeout', function($sce, $timeout){
return{
require : '?ngBindHtml',
scope:{value:"=ngBindHtml"},
link : function(scope, elm, attr, ngBindHtml)
{
$timeout(function()
{
var ck_inline;
elm.attr("contenteditable", "true");
CKEDITOR.disableAutoInline = true;
ck_inline = CKEDITOR.inline(elm[0]);
if (!attr.ngBindHtml)
return;
ck_inline.on('instanceReady', function()
{
ck_inline.setData(elm.html());
});
function updateHtml()
{
scope.$apply(function()
{
scope.value = $sce.trustAsHtml(ck_inline.getData());
});
}
ck_inline.on('blur', updateHtml);
ck_inline.on('dataReady', updateHtml);
});
}
};
}]);
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