I have a contentEditable view that when i focusOut i get the html entered and save it.
But when i remove all text from the contenteditable and then focus out i get the error
Uncaught Error: Cannot perform operations on a Metamorph that is not in the DOM.
Please see this jsfiddle and delete the value1 text and focus out.
http://jsfiddle.net/rmossuk/Q2kAe/8/
Can anyone help with this ?
best regards
Rick
Your EditableView sets up a display binding to its content.value:
<script type="text/x-handlebars" data-template-name="editable">
{{view.content.value}}
</script>
Ember performs its binding-updating magic by wrapping the relevant parts with marker script tags. Have a look at the resulting DOM:
Now you make your view editable. As soon as the user completely deletes the view's contents you will notice that the surrounding script tags are also removed (by the browser). At the moment Ember tries to update the display it won't find the necessary script tags and thus complains.
I don't think that you can make this approach to work reliably with contenteditable, since you won't be able to control the browser leaving the Ember surroundings intact. I guess you will need to take care of the view updating yourself: remove the binding, create a content.value observer and update the DOM explicitly:
App.EditableView = Em.View.extend({
contenteditable: "true",
attributeBindings: ["contenteditable"],
_observeContent: (function() {
this._displayContent();
}).observes('content.value'),
didInsertElement: function() {
this._displayContent();
},
_displayContent: function() {
this.$().html(this.get('content.value'));
},
...
Here is a JSFiddle with a demo of this solution: http://jsfiddle.net/green/BEtzb/2/.
(You could of course also use an Ember.TextField which uses a regular input field and provides all the binding magic, if that's all you need.)
Related
I have an application where I want to make an editing area, just like this one on StackOverflow. I don't want to use the textAngular directive, because it's too hard to understand, so I found about this Javascript function, document.execCommand, which it seems to be exactly what I need.
The problem is that I can't make it work in AngularJs. It's not giving any error, it just doesn't do anything.
I have a content editable div:
<div contenteditable id="text"><h5>Select a part of this text!</h5></div>
a Bold button:
<i class="fa fa-bold" ng-click="wrapBold()"></i>
and the function:
$scope.wrapBold = function() {
document.execCommand('bold', false, null);
};
I have tried with $document, which I injected in the controller, but then it gives me an error saying
TypeError: undefined is not a function at Scope.$scope.wrapBold
textAngular actually uses document.execCommand internally (I'm the maintainer FYI).
Your code is pretty much correct, the problem you are facing is that when you click on that button you loose the focus/selection of the contenteditable area, so it has no where to insert it.
From memory you have to do two things; Make the element with the ng-click on it have the attribute unselectable="on" and also catch and prevent the mousedown event on the same element. Here's how we setup the buttons in textAngular: https://github.com/textAngular/textAngular/blob/ff8e48087f780d30f54e77b06f09e0b85f9517e9/src/taBind.js#L26-L39
The problem with $document is that you need to use $document[0] to get the actual HTML DOM element to be able to call execCommand.
I am new to DOJO. I have a custom widget , which uses a template file for the dialog box contents.
I am extending dijit.Dialog in the script file.
dojo.declare(
"custom.credentials",
[dijit._WidgetBase, dijit._Templated,dijit._WidgetsInTemplateMixin,**dijit.Dialog**],
{
templatePath: dojo.moduleUrl("custom", "templates/credentials.html"),
....
....
postCreate: function() {
this.inherited(arguments);
alert(this.containerNode);
alert(this.mainDIV);
},
});
My Template test file looks like this
<div data-dojo-attach-point="mainDIV">
Login Dialog Box template here
</div>
For some reason, when I alert on this.mainDIV, I get 'undefined'. It does not read the template file. Also, this.containerNode gives me 'HTMLDIVElement', (parent dijit dialog DIV).
I am not able to figure out after a lot of trial error where exactly the issue is. Any help would be greatly appreciated.
Calling code
function opnPop(){
var pop= dijit.byId("customPopup");
pop.show();
}
<div dojoType="custom.credentials" id="customPopup"/>
Note : *When dijit.Dialog is not extended* it reads the template file without any problem, I.e, I am able to access this.mainDIV.innerHTML , that contains my own inner html contents.
Thank you.
If Dialog has to be sub-classed, then it must be the base class. Here, it seems that it is used as a mixin. Anyways, the problem is with the template that is used.
The template will be parsed and used by the code in Dialog. So, the template mentioned here has nothing but a div element with an attach point. There is no "containerNode" element (ie. attach point) and you are trying to access it in your js code, which will give error.
More important, the "titleBar" & "titleNode" elements are also missing form template, which will give errors while parsing the template. In order to avoid that, the code part that uses these elements need to be removed from js, to avoid error. So the widget creation will be successful. Try with the standard dijit.Dialog's template.
Add the data-dojo-attach-point="mainDIV" to the top level Dialog's div in the template.
In template, more things can be added, which won't cause any issues. But, if removed anything, will cause problem. If we are sub-classing a class/widget, we need to comply to the existing code.
I am trying to change value of an Input Textbox using several options of dojo but somehow those are not working. On the other hand when I am trying to change the text using document.getElememtById option I am able to do so. Can someone please explain why my dojo options are not working ?
if (response.responseJSON.errorMessage){
dom.byId("AuthInfo").innerHTML=response.responseJSON.errorMessage;
// dom.byId("AuthPassowrd").value="";
// domAttr.set("AuthPassowrd", "value", "");
// domConstruct.empty("AuthPassword");
document.getElementById("AuthPassword").value="";
}
and my html code is-
<input type="password" placeholder="Enter password" id="AuthPassword"/>
I'm not sure if it's a typo in this code only, but you wrote "AuthPassowrd" in stead of "AuthPassword". If it's only the case here (and not the real code), read my original answer.
Original answer
Are you sure you imported the correct modules (dojo/dom, dojo/dom-attr and dojo/dom-construct)? The examples are working fine for me. I made a JSFiddle to show you how it works. You can import these modules by using:
require(["dojo/dom", "dojo/dom-attr", "dojo/dom-construct"], function(dom, domAttr, domConstruct) {
// Here you can use dom, domAttr and domConstruct
});
Make sure the DOM is loaded before you execute your commands. Operations on DOM nodes can only be executed when that part of the DOM (or the entire page) is loaded. Usually you can wait until the DOM is ready with the dojo/domReady! plugin:
require(["dojo/domReady!], function() {
// Will only be executed when the dom is ready
});
In your third commented line of code you use domConstruct.empty("AuthPassword");. This won't work for clearing the input field but is used to delete all child nodes from a DOM node. The value of the textbox is not a childnode, so it won't work.
You should just replace this:
domAttr.set("AuthPassowrd", "value", "");
with:
domAttr.set(dom.byId("AuthPassword"), "value", "");
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.
I'm just getting my feet wet with Ember.js, and I've hit something that I'm sure I'm not understanding.
I've got a selected object controller. It has content, which is an Ember.Object, which is the currently selected model. The model has a property (isDirty), and basically I'd like my save button on my form to be enabled only when the object is dirty and needs to be saved.
I've managed to bind up the form just fine, but the isEnabledBinding property on the save button is either not doing anything or I'm not hooking up the binding properly.
I've prepared a jsfiddle demonstrating my basic set up.
http://jsfiddle.net/blargity/fqc73/1/
How do I get the button to be enabled only when isDirty is true? The bindings should also work if the content property on the selected object controller changes.
I found a way to do this without using the now-deprecated Ember.Button.
In the handlebars template:
<button {{action "save" target="controller"}} {{bindAttr disabled="view.isNotDirty"}}>Save</button>
In the view:
isNotDirty: function(){
return !this.get('controller.content.isDirty')
}.property('controller.content.isDirty').cacheable()
(With the version of Ember I have, Ember.Binding.not does not exist. Maybe I need to update, but the docs don't show it either so perhaps it was actually removed.)
The problem is that there is no isEnabled property on Ember.Button. You need to bind to the disabled property.
One possibility is to create a custom Ember.Button which handles this for you, see http://jsfiddle.net/LabpW/.
Handlebars:
{{#view App.SaveModelButton modelBinding="model"}}Save{{/view}}
JavaScript:
App.SaveModelButton = Ember.Button.extend({
disabledBinding: Ember.Binding.not('model.isDirty')
});
The used Ember.Binding.not is just a shortcut for writing your own computed property, which would look like this:
App.SaveModelButton = Ember.Button.extend({
disabled: function() {
return !Ember.getPath(this, 'model.isDirty');
}.property('model.isDirty').cacheable()
});
I also refactored your code a bit:
You mixed create and extend: use create for instances and extend for classes. There is a good blog post about this
It's kind of a convention to use lowerCase for instances and UpperCase for classes, so it should be App.controller instead of App.Controller