I have a DOJO Editor that I add in JS using the method createEditor
require(["dijit/Editor"],
function(Editor){
this.createEditor = function(idToReplace){
var myEditorA = new Editor({
height: '50px',
plugins:['bold','italic']
}, document.getElementById(idToReplace));
myEditorA.startup();
}
});
I need the text inside the Editor after it has been changed.
I hooked up the method getEditorText but it is failing to do as I want it to do.
require(["dijit/Editor"], "dojo/dom",
function(Editor, dom){
this.getEditorText = function(idofEditor){
//Editor myEditor =Editor(null, dom.byId(idofEditor)); does not work either
var myEditor = dom.byId(idofEditor);
var content = myEditor.get("value");
});
The value that I need is stored in the attribute "value" in the Editor.
If I store myEditorA in a global variable I can get the content but I need the correct syntax to avoid working with unnecessary global variables
In Dojo widgets (dijit) and DOM nodes are treated seperately. For DOM nodes you indeed need to use the dojo/dom module and the function byId(). For widgets however, you need the dijit/registry module and then you can get the widget by its DOM node like this:
require(["dijit/registry", "dojo/dom"], function(registry, dom) {
var myEditor = registry.byNode(dom.byId(idofEditor));
});
But because the registry also saves your editor with the same ID as your DOM node, you can also access it directly (without using the DOM node) like this:
require(["dijit/registry"], function(registry) {
var myEditor = registry.byId(idofEditor);
});
I made an example JSFiddle which you can find here.
Related
How do I access a virtual dom element to change its contents using Mithril? I am new to Mithril and still trying to figure things out. For example, I want to access the third div with id "three" and change it's contents to "Blue Jays" without touching any of the other div's.
Thanks.
<div id='main'>
<div id='one'>Yankees</div><br>
<div id='two'>Red Sox</div><br>
<div id='three'>Orioles</div>
</div>
In mithril, like in react/vue/angular, you dont act on the actual DOM directly. Instead, you define the outcome that you want, so for example, to render the DOM tree that you posted you would do something like this:
var my_view = {
view: vnode => m('div#main', [
m('div#one', 'Yankees'),
m('div#two', 'Red Sox'),
m('div#three', 'Orioles')
])
}
m.mount(root, my_view)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.js"></script>
<div id="root"></div>
the m(...) functions inside the array have a string as their second argument, that makes the output static, but we can change that to a variable:
var my_view = {
oninit: vnode => vnode.state.fave_team = 'Orioles',
view: vnode => m('div#main', [
m('div#one', 'Yankees'),
m('div#two', 'Red Sox'),
m('div#three', vnode.state.fave_team)
])
}
m.mount(root, my_view)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.js"></script>
<div id="root">
</div>
In this case I used the state property of the vnode argument, but you can also use a third party state manager like flux or any other.
Now that we have it as a variable, it will show the current value on every call m.redraw(), most of the times we dont have to do this call ourselves, for example:
var my_view = {
oninit: vnode => {
vnode.state.fave_team = 'Orioles'
},
view: vnode => m('div#main', [
m('div#one', 'Yankees'),
m('div#two', 'Red Sox'),
m('div#three', vnode.state.fave_team),
m('button', { onclick: () => vnode.state.fave_team = 'Dodgers' }, 'Change')
])
}
m.mount(root, my_view)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/2.0.4/mithril.js"></script>
<div id="root"></div>
And thats it, any dynamic content in your DOM elements you set it as a variable/property in an object.
One of the beautiful things about mithril is that it doesnt force you to do things one specific way, so if you really want to work on the actual DOM node, there are lifecycle events that you can attach to any virtual node ("vnode")
You can easily capture the HTMLElement (i.e., HTMLInputElement) with the Mithril Lifecycle event of oncreate(). This is an actual example from my code (in TypeScript) where I need to hook up a few event listneres after the canvas element was created and its underlying DOM is available to me at "raw" HTML level. Once you get a hold of dom, then I manipulate that element directly. Many people think that why not use oninit(), but oninit() is before the generation of dom, so you will not get the element back at that stage.
Now, if you just do that, you will likely be posting another question - "Why the browser views not updating?" And that's because you do have to manually do a m.redraw() in your event handlers. Otherwise Mithril would not know when the view diffs to be computed.
const canvas = m(`.row[tabIndex=${my.tabIndex}]`, {
oncreate: (element: VnodeDOM<any, any>) => {
const dom = element.dom;
dom.addEventListener("wheel", my.eventWheel, false);
dom.addEventListener("keydown", my.eventKeyDown, false);
}
},
I have a custom widget which extends _WidgetBase, _TemplatedMixin with template
<div dojoAttachPoint="widget">
<div dojoAttachPoint="title">${name}</div>
<div dojoAttachPoint="dnmschart"></div>
</div>
and another widget which extends above widget
require([
'dojo/_base/declare',
'my/widget/view/AbstractWidget'
], function (declare, AbstractWidget) {
return declare("my.widget.view.AbstractChart", [AbstractWidget], {
constructor:function(){
},
buildRendering: function(){
this.inherited(arguments);
var gridDiv = document.createElement("div");
gridDiv.setAttribute("dojoAttachPoint", "gridPlaceHolder");
},
postCreate:function(){
this.inherited(arguments);
//Here I could not get newly created node gridPlaceHolder
console.log(" POST CREATION");
}
});
});
When I print in console (Break point in post create method)
this.domNode
It shows newly created node at last in document(last node in above template)
<div dojoattachpoint="gridPlaceHolder"></div>
But I could not access gridPlaceHolder attach point in post create method.
Is there anything else need to configure?
Please help me on this:)
data-dojo-attach-point (which you should use for 1.6+ instead of dojoAttachPoint) allows you to have handles for dom nodes in your template.. It is parsed by _TemplatedMixin's buildRendering(), so it will be available in your buildRendering method just after this.inherited line.
You can not set data-dojo-attach-point using setAttribute, it can only be defined in templates to be parsed by TemplatedMixin. If you need your child widget to add some markup in addition to what there is in its parent's template, you can define a variable in your parent's markup, and overwrite it in your child widget:
Your AbstractWidget template:
<div data-dojo-attach-point="widget">
<div data-dojo-attach-point="title">${name}</div>
<div data-dojo-attach-point="dnmschart"></div>
${childMarkup}
</div>
And then you need to add your additional markup in child's buildRendering, before this.inherited:
require([
'dojo/_base/declare',
'my/widget/view/AbstractWidget'
], function (declare, AbstractWidget) {
return declare("my.widget.view.AbstractChart", [AbstractWidget], {
buildRendering: function(){
this.childMarkup = '<div data-dojo-attach-point="gridPlaceHolder"></div>';
this.inherited(arguments);
}
});
As stafamus said, the primary problem here is that you're attempting to assign data-dojo-attach-point or dojoAttachPoint to a node after the template has already been parsed (which happens during the this.inherited call in your buildRendering.
Going beyond that, given the code in the original post, it also appears you're never actually adding the markup you create in buildRendering to your widget's DOM at all - you've only created a div that is not attached to any existing DOM tree. I'm a bit confused on this point though, since you claim that you are seeing the markup for the node you added, which shouldn't be possible with the code above, or the code in stafamus' answer.
Rather than attempting to dump extra markup into your template, you might as well do the programmatic equivalent to what an attach point would be doing in this case anyway: create your DOM node, attach it to your widget's DOM, and assign it to this.gridPlaceHolder. e.g.:
buildRendering: function () {
this.inherited(arguments);
this.gridPlaceHolder = document.createElement('div');
this.domNode.appendChild(this.gridPlaceholder);
}
I'm using Dojo and would like to create a tree like structure. However, I'd like to be able to display content within the tree once the end node in a particular branch has been expanded. e.g.
top
- a branch
-- last item in this branch
[some content such as a div, span, image etc]
-- another item in this branch
[some more content]
etc
Does anyone know if this can be achieved using dijit Tree and if so, any pointers?
After digging around in the docs I've found a way to do this. It's not simple so thought I'd share. This page has an example of how to display a tree node with a rich text label rather than just text. This involves declaring your own class that inherits from Tree._TreeNode, allowing you to control it's creation. This same technique can be used.
When creating a Tree, I override the _createTreeNode function as follows:
_createTreeNode: function (args) {
if (args.item.type === "content") {
return new LayerManagerContentNode(args);
} else {
return new Tree._TreeNode(args);
}
}
In my store I add an object to represent the content that I want to display inline and give it a type of 'content'.
I create a class that inherits from Tree._TreeNode as follows:
define([
"dojo/_base/declare",
"dojo/_base/lang",
"dojo/dom",
"dojo/dom-construct",
"dojo/on",
"dijit/form/Button",
"dijit/Tree"
], function (declare, lang, dom, domConstruct, on, Button, Tree) {
return declare("my/ui/platforms/desktop/parts/LayerManagerContentNode", [Tree._TreeNode], {
// summary:
// ...
constructor: function () {
},
postCreate: function () {
var button = new Button({
label: "Test"
});
this.domNode.innerHTML = "<div></div>";
this.domNode.innterText = "";
button.placeAt(this.domNode, "first");
}
});
});
in the postCreate, I create a button (this was just for testing, I'll probable create a content pane or something to further populate) to be displayed in place of the usual tree node. I then replace the tree nodes innerHTML and innerText to hide what would normally be displayed, en voila, it works!
I dare say there are better ways to do this so if anyone comes along and has one, please add it.
<div dojoType="dojo.Dialog" id="alarmCatDialog" bgColor="#FFFFFF" bgOpacity="0.4" toggle="standard">
<div class='dijitInline'>
<input type='input' class='dateWidgetInput' dojoAttachPoint='numberOfDateNode' selected="true">
</div>
how to show this dialog I tried dijit.byId('alarmCatDialog').show();
The above code is a template and I called dijit.byId('alarmCatDialog').show() from the .js file .
dojo.attr(this.numberOfDateNode) this code works and I got the data .but if I change dojoattachpoint to id then I try dijit.byId('numberOfDateNode') will not work;
Your numberOfDateNode is a plain DOM node, not a widget/dijit, i.e. javascript object extending dijit/_Widget, which is the reason you cannot get a reference to it via dijit.byId("numberOfDateNode"). Use dojo.byId("numberOfDateNode") instead and you are all set.
dojoAttachPoint or its HTML5 valid version data-dojo-attach-point is being used inside a dijit template to attach a reference to DOM node or child dijit to dijit javascript object, which is the reason dijit.byId('alarmCatDialog').numberOfDateNode has a reference to your <input type='input' class='dateWidgetInput' .../>.
The main reason to use data-dojo-attach-point is that:
you can create multiple instances of dijit and therefore your template cannot identify nodes/dijits by IDs as you will have multiple nodes/dijits with the same ID
it's an elegant declarative way, so your code won't be full of dijit.byId/dojo.byId.
It is important to keep track of what is the contents and which is the template of the dijit.Dialog. Once you set contents of a dialog, its markup is parsed - but not in a manner, such that the TemplatedMixin is applied to the content-markup-declared-widgets.
To successfully implement a template, you would need something similar to the following code, note that I've commented where attachPoints kicks in.
This SitePen blog renders nice info on the subject
define(
[
"dojo/declare",
"dojo/_base/lang",
"dijit/_Templated",
"dijit/_Widget",
"dijit/Dialog"
], function(
declare,
lang,
_Templated,
_Widget,
Dialog
) {
return declare("my.Dialog", [Dialog, _Templated], {
// set any widget (Dialog construct) default parameters here
toggle: 'standard',
// render the dijit over a specific template
// you should be aware, that once this templateString is overloaded,
// then the one within Dialog is not rendered
templateString: '<div bgColor="#FFFFFF" bgOpacity="0.4">' +// our domNode reference
'<div class="dijitInline">' +
// setting a dojoAttachPoint makes it referencable from within widget by this attribute's value
' <input type="input" class="dateWidgetInput" dojoAttachPoint="numberOfDateNode" selected="true">' +
'</div>' +
'</div>',
constructor: function(args, srcNodeRef) {
args = args || {} // assert, we must mixin minimum an empty object
lang.mixin(this, args);
},
postCreate: function() {
// with most overrides, preferred way is to call super functionality first
this.inherited(arguments);
// here we can manipulate the contents of our widget,
// template parser _has run from this point forward
var input = this.numberOfDateNode;
// say we want to perform something on the numberOfDateNode, do so
},
// say we want to use dojo.Stateful pattern such that a call like
// myDialogInstance.set("dateValue", 1234)
// will automatically set the input.value, do as follows
_setDateValueAttr: function(val) {
// NB: USING dojoAttachPoint REFERENCE
this.numberOfDateNode.value = val;
},
// and in turn we must set up the getter
_getDateValueAttr: function() {
// NB: USING dojoAttachPoint REFERENCE
return this.numberOfDateNode.value;
}
});
});
How can I receive all events attached to an element with dojo?
dojo.query('#mydiv') // which events does #mydiv has?
To get all events on a DOM element:
// Get my div
myDiv = dojo.byId("myDiv");
// Obtain all event-related attributes
var events = dojo.filter(
myDiv.attributes,
function(item) {
return item.name.substr(0, 2) == 'on';
}
);
// Execute first found event, just for fun
eval(events[0].value);
If you get myDiv using dojo.query, remember that dojo.query returns an array, so your element would be in myDiv[0].
This solution does not work with events attached with dojo.connect. There probably is a way to extract this info from Dojo inner workings, but you would have to delve into the source code to understand how.
Another option is that you explicitly manage all dojo.connect events with a global registry. You could use dojox.collections to make this easier. For example, creating a global registry whose keys will be the dom nodes, and values will be the handles returned by dojo.connect (these handles contain the dom node, the type of event and the function to execute):
// On startup
dojo.require(dojox.collections.Dictionary);
eventRegistry = new dojox.collections.Dictionary();
...
// Registering an event for dom node with id=myDiv
var handle1 = dojo.connect(dojo.byId("myDiv"), "onclick", null, "clickHandler");
// Check if event container (e.g. an array) for this dom node is already created
var domNode = handle1[0];
if (!eventRegistry.containsKey(domNode))
eventRegistry.add(domNode, new Array());
eventRegistry.item(domNode).push(handle1);
...
// Add another event later to myDiv, assume container (array) is already created
var handle2 = dojo.connect(dojo.byId("myDiv"), "onmouseover", null, "mouseHandler");
eventRegistry.item(domNode).push(handle2);
...
// Later get all events attached to myDiv, and print event names
allEvents = eventRegistry.item(domNode);
dojo.forEach(
allEvents,
function(item) {
console.log(item[1]);
// Item is the handler returned by dojo.connect, item[1] is the name of the event!
}
);
You can hide the annoying check to see if event container is already created by creating a subclass of dojox.collections.Dictionary with this check already incorporated. Create a js file with this path fakenmc/EventRegistry.js, and put it beside dojo, dojox, etc:
dojo.provide('fakenmc.EventRegistry');
dojo.require('dojox.collections.Dictionary');
dojo.declare('fakenmc.EventRegistry', dojox.collections.Dictionary, {
addEventToNode : function(djConnHandle) {
domNode = djConnHandle[0];
if (!this.containsKey(domNode))
this.add(domNode, new Array());
this.item(domNode).push(djConnHandle);
}
});
Using the above class you would have to dojo.require('fakenmc.EventRegistry') instead of 'dojox.collections.Dictionary', and would simply directly add the dojo connect handle without other checks:
dojo.provide('fakenmc.EventRegistry');
eventRegistry = new fakenmc.EventRegistry();
var handle = dojo.connect(dojo.byId("myDiv"), "onclick", null, "clickHandler");
eventRegistry.addEventToNode(handle);
...
// Get all events attached to node
var allEvents = eventRegistry.item(dojo.byId("myDiv"));
...
This code is not tested, but I think you get the idea.
If its only for debugging purpose. You can try dijit.byId("myId").onClick.toString(); in your firebug console and you can see the entire onclick code this works even if the function is anonymous you can view the content of anonymous content.