Unable to read data from dynamically added CKEditor textarea - javascript

We are currently working on a java web application, where one of the jsp pages will have dynamically generated rich text areas and we are using CKEditor for that purpose. I'm able to generate the text editors dynamically. There is button on the jsp page, on clicking it a java script method adds a new row, with textarea, to the table. Once the row is added, we are using the CKEDITOR.replace('editorName'); method to replace the textarea to CKEditor. Below is the code:
jsp:
<table id="StepsList" style="float: left" width="100%" ></table>
We are maintaining a variable rowNum to keep a track of number of textarea's created.
script:
var step = 'step'+rowNum;
$("#StepsList").append("<tr><td><div class='richTextareaWrapp bottmsp' style='margin-top:10px;'><textarea cols='40' id="+step+" name="+step+"></textarea></div></td></tr>");
CKEDITOR.replace(step);
To read the content of the generated CKEditors, we are iterating based on rowNum. Below is the code written in java script file:
script:
for(var j=1;j<=rowNum;j++){
obj = new Object();
step = '#step'+j;
$(step).ckeditor(function( textarea ){
obj.value=$(textarea).val();
});
jsonStepsArr.push(obj);
}
This throws an error saying "uncaught exception: The editor instance "step1" is already attached to the provided element."
I have gone through similar posts on stackoverflow and google for solution, most of them suggest to replace or destroy the instance. But it did not serve my purpose. Can anyone point out my mistake or if I have to add any code to make this work?
Thanks in advance.

Be consistent in your creation/accessing techniques.
Looks like if you're going to create an editor with normal CKEDITOR.replace call like:
CKEDITOR.replace( 'editor1' );
And then access it with a jQuery call like:
$( '#editor1' ).ckeditor( function( textarea ) {
// Do whatever...
} );
It won't play nice with each other.
Your solution:
So as a result either change your first call to:
$('#'+step).ckeditor();
Or in second call instead using jQuery, just access instance directly:
CKEDITOR.instances[ 'step'+j ].getData()

Related

Modify HTML Content Created by 3rd Party JS Script

I am creating a custom sign in experience for a customer using okta Sign in Widget. As part of this 'widget' the function creates an HTML login form. One of the tags this generates I want to modify the contents of after it has been generated on page load by the Okta widget.
I've created a fiddle where I used the following code to modify the contents but it doesn't seem to be working.
$(document).ready(function(){
var headingClass = document.getElementsByClassName("okta-form-title");
headingClass.innerHTML = "<h2>Public Offers</h2>";
}) ;
Please could someone advise on how to get this working.
getElementsByClassName will give you an array of elements with that class name. So you need to iterate over it, or if you are sure there is only one element, use getElementsByClassName[0]
Example:
$(document).ready(function(){
var headingClass = document.getElementsByClassName("okta-form-title");
headingClass[0].innerHTML = "<h2>Public Offers</h2>";
}) ;
More information: https://developer.mozilla.org/en/docs/Web/API/Document/getElementsByClassName

AngularJS with MVC dynamically get html, append to body, and bind a controller

I am new to AngularJS with a jQuery background. For what I thought would be a simple task I am just finding it to be increasingly difficult. I have looked around on how to dynamically add html and bind to a controller but I just have not found my particular situation.
This is what I am trying to accomplish. I'll want to keep it simple for now with a simple dialog box. Basically, suppose I want to create my own custom dialog box. Suppose based on a button click I want to display the message "Are you sure you want to so and so" with the buttons yes, no, cancel. Then based on the button click, I'd like to perform a specific operation, users with windows development will be familiar with this.
First I must construct my message and my dialog box html based on the button clicked, append that output html to the document body as position absolute, and then once done with this remove the html from the document body.
In jQuery I can simply do this
...somewhere in code
var html = "<div id='123' class='dialog-box'><button id='yesButton'></button>
...elements for no and cancel</div>";
DisplayDialog("123", html);
...
function DisplayDialog(elementId, html) {
$(document.body).append(html);
var dElement = $(document.body).find("#" + elementId);
$(dElement).find("#yesButton").on("click" function () {
...code
$(dElement).remove();
});
...code for no, and cancel events
}
I just can't understand how to do this simply the angular way. Basically, I want to be able to get html, append it somewhere (whether in the body, or in a div element etc), and be able to interact with it using the $scope. I kept it simple for now for a dialog box, if I can understand this I can apply to much more complex operations where I might need to retrieve partial views in my MVC application and append it to a div
Its pretty straightforward in angular, this shouldn't be to hard for you given the jquery background:
var myEl = angular.element( document.querySelector( '#divID' ) );
myEl.append('Hi<br/>');
https://docs.angularjs.org/api/ng/function/angular.element
Another way:
You then use ng-bind in the html and set it to a $scope variable that represents the html:
<div ng-bind-html="divHtmlVar"></div>
$scope.divHtmlVar = '<b>main html</b>';
Relevant blog post:
http://blog.sodhanalibrary.com/2014/08/append-or-prepend-html-to-div-using.html

Replace CKEditor by class after .load()

I am using CKEditor for my website's blog posts but have an issue where after loading all the bog posts via .load() they no longer get replaced by CKEditors.
This is done example:
$("#container #postholder").load("http://url.com/viewblog.php?id=155 #container #postholder");
First, I had issues with the scripts that were called upon by items that were loaded via the .load() method. I solved this by changing the button call to this:
$(document).on('click','.edity',function(){ });
The buttons now work, but the CKEditor isnt.
Lets say I have 5 different instances that are on the page, they all have the generic class of ckeditor so they all work.
However, after the .load() of the items, they are not changed to CKEditors and instead stay text areas.
To solve this I tried this when clicking the 'edit' button:
$(document).on('click','.edity',function(){
CKEDITOR.replace('.ckeditor');
});
That does not work, I then tried using the name of the CKEditors so:
$(document).on('click','.edity',function(){
CKEDITOR.replace('editorName');
});
This works, even after the .load(), but it only works for the first instance. All of the other CKEditors are not changed into the CKEditor.
I cant see how to get around this...
Any one understand?
Editors are created like so:
This is in a foreach loop for each blog post result. The ckEID variable is the posts ID + 1.
<div class="editor">
<textarea name="muffin" id="'.$ckEID.'" class="ckeditor">'.$text.'</textarea>
</div>
I use this:
$(document).on('click','.edity',function(){
$(this).parent().find('.editor').toggle();
CKEDITOR.replace('ckeditor');
});
To convert the text area when the edit button is clicked.
Just tried using replaceAll and the error console showed e.g.
uncaught exception: The editor instance "message" is already attached to the provided element.
I have other text areas on the page and it seems that everything is getting messed up when using replaceAll.

Inline Editing But Instance Doesn't Exist

I have my own custom non-jQuery ajax which I use for programming web applications. I recently ran into problems with IE9 using TinyMCE, so am trying to switch to CKeditor
The editable text is being wrapped in a div, like so:
<div id='content'>
<div id='editable' contenteditable='true'>
page of inline text filled with ajax when links throughout the site are clicked
</div>
</div>
When I try to getData on the editable content using the examples in the documentation, I get an error.
I do this:
CKEDITOR.instances.editable.getData();
And get this:
Uncaught TypeError: Cannot call method 'getData' of undefined
So I figure that it doesn't know where the editor is in the dom... I've tried working through all editors to get the editor name, but that doesn't work-- no name appears to be found.
I've tried this:
for(var i in CKEDITOR.instances) {
alert(CKEDITOR.instances[i].name);
}
The alert is just blank-- so there's no name associated with it apparently.
I should also mention, that despite my best efforts, I cannot seem to get the editable text to have a menu appear above it like it does in the Massive Inline Editing Example
Thanks for any assistance you can bring.
Jason Silver
UPDATE:
I'm showing off my lack of knowledge here, but I had never come across "contenteditable='true'" before, so thought that because I was able to type inline, therefore the editor was instantiated somehow... but now I'm wondering if the editor is even being applied to my div.
UPDATE 2:
When the page is loaded and the script is initially called, the div does not exist. The editable div is sent into the DOM using AJAX. #Zee left a comment below that made me wonder if there is some other command that should be called in order to apply the editor to that div, so I created a button in the page with the following onclick as a way to test this approach: (adapted from the ajax example)
var editor,html='';config = {};editor=CKEDITOR.appendTo('editable',config, html );
That gives the following error in Chrome:
> Uncaught TypeError: Cannot call method 'equals' of undefined
> + CKEDITOR.tools.extend.getEditor ckeditor.js:101
> b ckeditor.js:252
> CKEDITOR.appendTo ckeditor.js:257
> onclick www.pediatricjunction.com:410
Am I headed in the right direction? Is there another way to programmatically tell CKEditor to apply the editor to a div?
UPDATE 3:
Thanks to #Reinmar I had something new to try. The most obvious way for me to test to see if this was the solution was to put a button above the content editable div that called CKEDITOR.inlineAll() and inline('editable') respectively:
<input type='button' onclick=\"CKEDITOR.inlineAll();\" value='InlineAll'/>
<input type='button' onclick=\"CKEDITOR.inline('editable');\" value='Inline'/>
<input type='button' onclick=\"var editor = CKEDITOR.inline( document.getElementById( 'editable' ) );\" value='getElementById'/>
This returned the same type of error in Chrome for all three buttons, namely:
Uncaught TypeError: Cannot call method 'equals' of undefined ckeditor.js:101
+ CKEDITOR.tools.extend.getEditor ckeditor.js:101
CKEDITOR.inline ckeditor.js:249
CKEDITOR.inlineAll ckeditor.js:250
onclick
UPDATE 4:
Upon further fiddling, I've tracked down the problem being related to json2007.js, which is a script I use which works with Real Simple History (RSH.js). These scripts have the purpose of tracking ajax history, so as I move forward and back through the browser, the AJAX page views is not lost.
Here's the fiddle page: http://jsfiddle.net/jasonsilver/3CqPv/2/
When you want to initialize inline editor there are two ways:
If element which is editable (has contenteditable attribute) exists when page is loaded CKEditor will automatically initialize an instance for it. Its name will be taken from that element's id or it will be editor<number>. You can find editors initialized automatically on this sample.
If this element is created dynamically, then you need to initialize editor on your own.
E.g. after appending <div id="editor" contenteditable="true">X</div> to the document you should call:
CKEDITOR.inline( 'editor' )
or
CKEDITOR.inlineAll()
See docs and docs.
You can find editor initialized this way on this sample.
The appendTo method has different use. You can initialize themed (not inline) editor inside specified element. This method also accepts data of editor (as 3rd arg), when all other methods (CKEDITOR.inline, CKEDITOR.replace, CKEDITOR.inlineAll) take data from the element they are replacing/using.
Update
I checked that libraries you use together with CKEditor are poorly written and cause errors you mentioned. Remove json2007.js and rsh.js and CKEditor works fine.
OK, so I have tracked down the problem.
The library I was using for tracking Ajax history and remembering commands for the back button, called Real Simple History, was using a script called json2007 which was intrusive and extended native prototypes to the point where things broke.
RSH.js is kind of old, and I wasn't using it to it's full potential anyway, so my final solution was to rewrite the essential code I needed for that, namely, a listener that watched for anchor (hash) changes in the URL, then parsed those changes and resubmitted the ajax command.
var current_hash = window.location.hash;
function check_hash() {
if ( window.location.hash != current_hash ) {
current_hash = window.location.hash;
refreshAjax();
}
}
hashCheck = setInterval( "check_hash()", 50 );
'refreshAjax()' was an existing function anyway, so this is actually a more elegant solution than I was using with Real Simple History.
After stripping out the json2007.js script, everything else just worked, and CKEditor is beautiful.
Thanks so much for your help, #Reinmar... I appreciate your patience and effort.

what happens when you use javascript to insert a javascript widget?

can anyone explain what happens when you use javascript to insert a javascript based widget?
here's my js code:
var para = document.getElementsByTagName("p");
var cg = document.createElement("div");
cg.setAttribute("class", "twt");
cg.innerHTML='<a href="http://twitter.com/share" class="twitter-share-button"
data-count="vertical" data-via="xah_lee">Tweet</a>
<script type="text/javascript" src="http://platform.twitter.com/widgets.js"></script>';
document.body.insertBefore(cg, para[1]);
it inserts the twitter widget, before the first paragraph. As you can see above, the twitter widget calls for a javascript that shows how many time the page has been tweeted.
doesn't work in Firefox, Chrome, but semi-works in IE8. What should be the expected behavior when this happens? Does the newly inserted js code supposed to execute? If so, how's it differ from if the code is on the page itself?
In order to execute the JS code you insert into a DIV via innerHTML, you need to do something like the following (courtesy of Yuriy Fuksenko at http://www.coderanch.com/t/117983/HTML-JavaScript/Execute-JavaScript-function-present-HTML )
function setAndExecute(divId, innerHTML) {
var div = document.getElementById(divId);
div.innerHTML = innerHTML;
var x = div.getElementsByTagName("script");
for (var i=0;i<x.length;i++) {
eval(x[i].text);
}
}
A slightly more advanced approach is here: http://zeta-puppis.com/2006/03/07/javascript-script-execution-in-innerhtml-the-revenge/ - look for <script> tags, take their conĀ­tent and create a new eleĀ­ment into the <head>.
innerHTML does not work to insert script tags (because the linked script, in most browsers, will fail to execute). Really, you should insert the script tag once on the server side and insert only the link at the location of each post (that is, if you are adding this to a blog home page that shows multiple posts, each with their own URLs).
If, for some reason, you decide that you must use one snippet of JavaScript to do it all, at least import the tweet button script in a way that will work, for example, the Google Analytics way or the MediaWiki way (look for the importScriptURI function). (Note that I do not know the specifics of the tweet button, so it might not even work.)

Categories

Resources