Extend YUI TreeView with Treeview Sortable - javascript

I'm using YUI3 to create an instance of Y.TreeView.
var treeview = new Y.TreeView({
lazyRender: false,
container: treeview,
nodes: jsonTreeFile
});
Now I want to extend this object to use it with TreeView.Sortable, which mixes in Y.Tree.Sortable. The constructor is TreeView.Sortable () (See TreeView.Sortable Api ).
How do I do this, so I can use the TreeView.Sortable methods on the treeview object?
Here is the full context:
YUI({
gallery: 'gallery-2013.07.31-22-47'}).use(
'gallery-sm-treeview', 'gallery-sm-treeview-sortable', function (Y) {
// Create a new TreeView in container with nodes.
treeview = new Y.TreeView({
lazyRender: false,
container: treeview,
nodes: jsonTreeFile
});
// Render the treeview inside the #treeId element.
treeview.render();
// Now, how do I extend and sort the treeview object?
});

In case anyone is interested in the solution, this is how subclassing in YUI works (thanks to Ryan Grove for helping out: codepen.io/rgrove/pen/vAuep)
YUI({
gallery: 'gallery-2013.07.31-22-47'
}).use('gallery-sm-treeview', 'gallery-sm-treeview-sortable', function (Y) {
var SortedTreeView = Y.Base.create('sortedTreeView', Y.TreeView, [Y.TreeView.Sortable], {
sortComparator: function (node) {
return node.label;
}
});
var treeview = new SortedTreeView({
container: '#treeview',
nodes: [{label: 'hi!'}, {label: 'hello!'}]
});
treeview.render();
});

Related

How to obtain this ref to declaring class from Dojo gridx detailProvider (Dod module)

Using the Dojo framework.
I have a 2 nested grid. Grid 1 uses a Dod with a detailprovider to load details on demand when one clicks a expand icon. When pressed this opens a nested grid. I need to track changes made in both grids. In the declaring class I've got an array that keeps track on changes made. The problem is that I can't access the array from a detailprovider. Since I've to conform to the protocol which gridx later invokes. What can I do to obtain a ref to the declaring class
var myDeclaringClass = declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin], {
array: [],
initGrid: function(){
var grid = new Grid({
store: store,
structure: columns,
modules: [ {
moduleClass: Dod,
showExpando: true,
detailProvider: this.myDetailProvider
}]
});
// .... grid.placeAt() .. grid.startup()
},
myDetailProvider: function(parentGrid, rowId, detailNode, rendered) {
// construct Nested Grid ...
// How to obtain this reference here?
// to access this.array?
rendered.callback();
return rendered;
}
retrun myDeclaring;
}
EDIT:
I have also tried with a static var like:
statics: { array: [] }
But here I will stille need a instance ref to access it.
Try something like this
var myDeclaringClass = declare([_WidgetBase,_TemplatedMixin,_WidgetsInTemplateMixin], {
array: [],
var globalref : this,//here i'm assigning 'this' i.e. class level ref to the variable
initGrid: function(){
var grid = new Grid({
store: store,
structure: columns,
modules: [ {
moduleClass: Dod,
showExpando: true,
detailProvider: this.myDetailProvider
}]
});
// .... grid.placeAt() .. grid.startup()
},
myDetailProvider: function(parentGrid, rowId, detailNode, rendered) {
// construct Nested Grid ...
// How to obtain this reference here?
// to access this.array?
globalref.array//should give you access to the array
rendered.callback();
return rendered;
}
retrun myDeclaring;
}

Accessing variables across different scopes in Javascript & YUI 3

I'm new to YUI 3 and YUI in general. I'm trying to pass data between classes and methods.
In this example I'm using the gallery-sm-treeview plugin to build a file tree. There's a class named TreeView to initialize and render the tree. There's another class named MenuBar where I want to access some of the plugin-specific methods through TreeView's getter method.
However, the variable var treeview inside the YUI().use() scope is of course not accessible from outside. How to do it?
YUI.add('treetool.TreeView', function(Y) {
Y.treetool.TreeView = Class.extend({
init : function(elementId) {
YUI({
gallery: 'gallery-2013.06.20-02-07'}).use('gallery-sm-treeview', function (Y) {
// Create a new TreeView with a few nodes.
var treeview = new Y.TreeView({
// Tell the TreeView where to render itself.
container: elementId,
// Populate the treeview with some tree nodes.
nodes: [
{label: 'Node 1'},
{label: 'Node 2', children: [
{label: 'Child 1'},
]
});
// Render the treeview inside the #treeview element.
treeview.render();
});
},
getSomeData : function () {
return treeview.getSelectedNodes();
}
});
}, '0.0.1', {
requires : [ 'jquery' ]
});
and
YUI.add('treetool.MenuBar', function(Y) {
Y.treetool.MenuBar = Class.extend({
init : function(treeObj) {
var someData = treeObj.getSomeData();
},
});
}, '0.0.1', {
requires : [ 'jquery' ]
});
It might not be the "best" way to do it, but one way would be to define the treeview variable in a scope that is available in both places.
YUI.add('treetool.TreeView', function(Y) {
var treeview;
//...
and
treeview = new Y.TreeView({ // removed "var "

Is there a nice way to make a Kendo custom widget, using Typescript classes?

The documentation for creating custom Kendo widgets is good enough, and leads to something like:
declare var kendo: kendo;
// To be able to get types, we can express the widget as this interface
interface ICustomDatePicker {
options: () => kendo.ui.DatePickerOptions;
}
; (function ($:JQueryStatic, window:any, document:Document, undefined?) {
var CustomDatePicker: ICustomDatePicker = (<any>kendo.ui.DatePicker).extend({
init: function (element, options:kendo.ui.DatePickerOptions) {
var self = this;
// base call to initialize widget
(<any>kendo.ui.DatePicker).fn.init.call(self, element, options);
},
options: {
// the name is what it will appear as off the kendo namespace (i.e. kendo.ui.CustomDatePicker).
// The jQuery plugin would be jQuery.fn.kendoCustomDatePicker.
name: "CustomDatePicker"
}
});
// This makes it work as a jQuery plugin
(<any>kendo.ui).plugin(CustomDatePicker);
})(jQuery, window, document);
A typescript file with that above, let's me do things like: $("#datePicker").kendoCustomDatePicker({}); and it all works beautifully.
My question is, is there a better way to write this in class form? My original thought is this:
module Foo {
class CustomDatePicker extends kendo.ui.DatePicker {
constructor(element, options) {
super(element, options);
}
}
(<any>kendo.ui).plugin(CustomDatePicker);
}
But that doesn't work (when calling the same $("#datePicker").kendoCustomDatePicker({});. This Gist gets closer, but I think the syntax is a bit funky - that the class doesn't extend the control directly. Any ideas?
Update 1
Looking at this answer, I'm trying to find a way to clean up setting the options by having it IN the class. I've gotten the following to semi-work, though it breaks down for some options and not others:
constructor(element: Element, options?: kendo.ui.TimePickerOptions) {
super(element, options);
$.extend(this.options, <kendo.ui.TimePickerOptions>{
format: "hh:mm tt",
parseFormats: ["HH:mm", "hh:mm tt"]
});
}
In this case, it respects that format and you can see it working. If you try and do the following:
$.extend(this.options, <kendo.ui.TimePickerOptions>{
format: "hh:mm tt",
parseFormats: ["HH:mm", "hh:mm tt"]
});
.. it doesn't work, doesn't parse the input at all.
There is a way but I am not 100% sure it qualifies as "nice". Here is some code which I wrote today and works:
class MyTreeView extends kendo.ui.TreeView
{
constructor(element: Element, options?: kendo.ui.TreeViewOptions) {
super(element, options);
}
static fn;
}
// kendo.ui.plugin relies on the fn.options.name to get the name of the widget
MyTreeView.fn = MyTreeView.prototype;
MyTreeView.fn.options.name = "MyTreeView";
// kendo.ui.plugin which comes with the Kendo TypeScript definitions doesn't include this overload
module kendo.ui {
export declare function plugin(widget: any, register?: Object, prefix?: String);
}
// register the plugin
kendo.ui.plugin(MyTreeView);
// extend the jQuery interface with the plugin method (needed to be used later)
interface JQuery {
kendoMyTreeView(options?: kendo.ui.TreeViewOptions): JQuery;
}
// use the plugin
$(function () {
$("#content").kendoMyTreeView({
dataSource: [
{
text: "Root",
items: [
{ text: "Child" }
]
}
]
});
});

What is the difference between these two codes?

I am new to ExtJs, just stepped into some basic things and found that its very hard to get started as a beginner.
Below are the two ways of implementing Ext button:
Sample1:
var nextBtn = new Ext.Button({
text: 'Next >>',
handler: function() {
Ext.getDom('form_main').submit();
},
id: 'next',
renderTo: 'next'
});
Sample2:
Ext.widget('button', {
text: 'some long title of my cool button',
scale: 'large',
cls: 'my-button',
width: 100,
renderTo: 'output'
});
My guess is beacuse of the version, it has changed. Please let me know what is the difference between these two codes.
Regards,
There are many ways to instantiate a class in ExtJS.
Take this definition as example:
Ext.define ('Ext.button.Button', {
alias: 'widget.button' ,
// here other properties and methods ...
});
Then you can chose one of these ways to instantiate Ext.button.Button:
First: javascript style
var button = new Ext.button.Button ({
// props and methods
});
Second: ExtJS style with Ext.create method
var button = Ext.create ('Ext.button.Button', {
// props and methods
});
Third: ExtJS style with Ext.widget method (it uses alias property)
var button = Ext.widget ('button', {
// props and methods
});
I suggest you to use the second or the third way because they use ExtJS dynamic loader: here's the documentation

Extjs: Tree, Selecting node after creating the tree

I have a simple TreePanel. I would like to select a particular node upon loading it. The nodes are from a remote file (json).
The tree is loading as expected. However, the node is not being selected. Firebug shows node as undefined. This perhaps because of the async property. But, I an unable to configure this other wise, or specify the node be selected.
Any suggestions welcomed, and thank you.
LeftMenuTree = new Ext.tree.TreePanel({
renderTo: 'TreeMenu',
collapsible: false,
height: 450,
border: false,
userArrows: true,
animate: true,
autoScroll: true,
id: 'testtest',
dataUrl: fileName,
root: {
nodeType: 'async',
iconCls:'home-icon',
expanded:true,
text: rootText
},
listeners: {
"click": {
fn: onPoseClick,
scope: this
}
},
"afterrender": {
fn: setNode,
scope: this
}
});
function setNode(){
alert (SelectedNode);
if (SelectedNode == "Orders"){
var treepanel = Ext.getCmp('testtest');
var node = treepanel.getNodeById("PendingItems");
node.select();
}
}
I use this code in the TreeGrid to select a node
_I.treeGrid.getSelectionModel().select(_I.treeGrid.getRootNode());
I haven't tried this in a TreePanel but since the TreeGrid is based on it I'll just assume this works. I used the load event of the loader to plugin similar code after the XHR request was done, so try to write your setNode function like this:
var loader = LeftMenuTree.getLoader();
loader.on("load", setNode);
function setNode(){
alert (SelectedNode);
if (SelectedNode == "Orders"){
var treepanel = Ext.getCmp('testtest');
treepanel.getSelectionModel().select(treepanel.getNodeById("PendingItems"));
}
}
this work for me...
var loader = Ext.getCmp('testtest').getLoader();
loader.on("load", function(a,b,c){
b.findChild("id",1, true).select(); // can find by any parameter in the json
});
I have documented a way to accomplish something very similar here:
http://www.sourcepole.ch/2010/9/28/understanding-what-s-going-on-in-extjs
what you'll need to make sure is that the node that you are selecting is visible. You can accomplish that by traversing the tree and node.expand()ing all the nodes parents (from the root down).
This is because the node isn't really selectable until the tree has been rendered. Try adding your node selection to an event listener listening for the render event.
If you're using a recent enough version of ExtJS then I find using ViewModels and the Selection config far easier for this kind of thing.
Something like:
LeftMenuTree = new Ext.tree.TreePanel({
renderTo: 'TreeMenu',
collapsible: false,
height: 450,
border: false,
userArrows: true,
animate: true,
autoScroll: true,
id: 'testtest',
dataUrl: fileName,
bind: {
Selection: '{SelectedNode}'
},
root: {
nodeType: 'async',
iconCls:'home-icon',
expanded:true,
text: rootText
},
listeners: {
"click": {
fn: onPoseClick,
scope: this
}
"afterrender": {
fn: setNode,
scope: this
}
});
(You'll need to either have a ViewModel set up in the TreePanel or the owning view)
Then assuming you're using a ViewController and setNode is a member:
setNode: function(){
var nodeToSelect = // code to find the node object here
this.getViewModel().set('Selection', nodeToSelect);
}
The nice thing about the ViewModel approach is that it seems to just handle all of the rendering / data loading issues automatically.

Categories

Resources