As the document said, TreeView in GTK4 has been deprecated since 4.10. The recommended replacement for it is ColumnView. However, I can't find clear documentation or example about how to build a treeView-like widget in GTK4 by ColumnView.
I found maybe TreeExpander related to it but I still don't know how to deal with it.
A very brief outline of what I did:
Familiarize yourself with how the new dynamic list widgets (Gtk.GridView and Gtk.ColumnView) work for a flat model (GLib.ListStore). There is example code in the Demo app.
Create a Gtk.TreeListModelCreateModelFunc function that takes a model item as a parameter and, if that item has children (e.g. is a folder in a filesystem model), creates and returns a Gtk.ListStore to hold the children. If the child items are already available then they can also be appended to the child model here. This means the child items are preloaded whether or not the row is expanded. For startup performance reasons, you might want to arrange to load them when the row is actually expanded which is more difficult - in this case you have to add a dummy child to the model else the expander will not be displayed.
Create a Gtk.SignalListItemFactory.
In the setup handler, create a display widget as usual then instead of using your display widget as child of the Gtk.ListItem, you create a Gtk.TreeExpander, and make that the child the Gtk.ListItem and make the display widget a child of the expander.
In the bind handler, get the display widget and model item from the supplied object. A complication here is that the object may be a Gtk.TreeListRow whose item might be another Gtk.TreeListRow so getting to the model item is harder. Bind the widget to the model item as usual. Then get the Gtk.TreeListRow from the Gtk.ListItem position and set the expander's list-row property to it.
If you delayed loading the child items then you would need to detect when the row is first expanded. You can connect to the notify signal for the Gtk.TreeListRow.expanded property to do this.
Use a Gtk.TreeListModel with a GLib.ListStore as its root_store as the model of a Gtk.ColumnView (after wrapping in Gtk.SelectionModel as usual). You must set the passthrough property to false else no expanders appear. If you are loading child items on demand then autoexpand should also be false.
If you are using a Gtk.ColumnView with multiple columns, you only need add the expander to the first column. Otherwise the factory signal handlers or similar to the flat model except the bind handler needs to be adapted for Gtk.TreeListRow parameter.
Simplifications and performance improvements may well be possible or later versions of Gtk4 may introduce some conveniences to make it less fiddly.
I am working on a file browser implementation using the above strategy, currently at https://github.com/elementary/files/tree/gtk4-treelistmodel but this may be merged into other branches (or abandoned!). Note that this branch is under development and contains unresolved bugs but the display of items works.
How can I force dom-elements depending on a binding (like the value-attribute of an input-element) to rerender even if the value of the binding has not changed.
Binding itself does not expose such a method and I was not able to use one of the other classes like Map in my code...
Interesting! Some one just asked a reverse question to avoid re-rendering a DOM element at Toomany DOM updates .
So, the answer to your question is reverse committing the PR mentioned in the other question.
I'm just picking up om.next and have run into a situation where I've got some form inputs realized as components which hold on to local state, e.g. validation state, actual input value, etc--this state is updated and accessed via om.next/update-state! and om.next/get-state. The trouble with this seems to be when I wrap the inputs in a form in a parent component I'm unsure how to get the state held by the input components. Is it better to pass along the parent component as a property of the input component? What about situations where there is no parent component?
It seems to me that there are 2 options for the use case you want to achieve:
pass the parent component as an argument as you said
have an entry in the global app-state that represents the current form being edited, which you can update via transact! irregardless of the component corresponding to the input. This way every component that represents an input knows where in the app-state to update itself (which key in the current form) — probably captured succintly in one mutation function.
1) is probably the easiest to implement given the code you have currently, but I always like to go for 2) because it doesn't deviate from the "single source of truth" opinion that Om Next recommends (and tries to enforce). Form data is in fact business data, which might not be desirable to have scattered in components. Testability is just one advantage that I immediately see from such approach.
I've been working with ExtJS for a good few months now, but still don't have a perfectly clear map of what's going on behind the scenes there. I'm just talking about the building blocks of the framework and their most basic functionality.
Ext.Component
Ext.Element
DOM.Element
DOM.Node (?)
CompositeElement (?)
Whatever else (?)
For each of the abovementioned I would like to know:
How to select: by ID, by class, via parent, find (OR children OR query OR select? WTF), siblings, ComponentQuery, DOM-query, CSS-query, etc..
How to manipulate in the tree: create, append, prepend, insert after this sibling, move to that parent, remove, destroy, etc..
How to manipulate on the screen: show, hide, fade, slide, move up, down, change size, etc..
How to identify related to each other: find DOM.Element knowing its Ext.Component, find Ext.Component knowing its DOM.Element, etc..
What is the dependency between them: what happens to the DOM.Element if its Ext.Component is hidden / destroyed / changed / moved, what happens to the Ext.Component if its Ext.Element is hidden / destroyed / changed / moved, etc.
I'm looking for a methodical and logically clear layout of how each is supposed to be used and is expected to behave. I am also hoping that the described functionality can be grouped in corresponding categories, e.g. would be nice to see complement traversing methods .up() and .down() next to each other, rather than alphabetically pages apart. Of course links and examples (which the official documentation lacks so badly) are also welcome!
You can find out a whole lot about the building blocks of ExtJS (known as Ext Core) from the manual for this: http://docs.sencha.com/core/manual/. I will try to add some knowledge and highlight some key points, but you should definitely read through that for a very informative overview.
Ext.Component
The building block for the OOP paradigm within ExtJS. Essentially, this is an Object that contains inherited functionality to serve as the basis for a specialized component that will be transformed by the framework into DOM elements that are shown as HTML.
The Sencha documentation is excellent for this. Here are a couple good places to start:
http://docs.sencha.com/extjs/4.2.1/#!/guide/layouts_and_containers
http://docs.sencha.com/extjs/4.2.1/#!/guide/components
Ext.Element vs DOM Element
As an JavaScript develop knows, a DOM element is just a JS object that represents a tag in the document's HTML. Essentially, Ext.Element is a wrapper object for a DOM element that allows for ExtJS to manipulate the object. Any DOM element on the page can be wrapped as an Ext.Element to allow for this additional functionality.
For example, take this HTML tag:
<div id="myDiv">My content</div>
You can access this using
var el = document.getElementById('myDiv')
and use the basic, built-in JavaScript DOM functionality on el. You could also access this using
var el = Ext.get('myDiv')
and have a whole additional set of functionality available to apply to that element using the ExtJS library
The Sencha docs are also excellent for this. See all the available functionality for Ext.Element here: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.dom.Element
Misc
You can get an Ext.Element from a component using the getEl() method:
var myComponent = Ext.create('Ext.Component', { html: 'my component' });
var el = myComponent.getEl();
You would rarely need to go the other way, to determine a component from a DOM element. There isn't much of a use case there unless you are really hacking something. A major reason for using a framework like ExtJS is to prevent needing to do something like this; if should develop entirely within the JavaScript, you should be able to avoid having a reference to a DOM element where you need to get its containing ExtJS component.
Niklas answered pretty well about how to select components and elements. The only things I would really add is that you can use up() and down() to select relative to a component. In this way, you should use itemId on components rather than the global identifier id (using id can cause difficult-to-debug errors if you are reusing components with the same ID).
Also, to add to Niklas's answer about showing/hiding components, the framework does indeed add some CSS to the component's element, depending on what the hideMode for the component is. Learn more about that property here: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.AbstractComponent-cfg-hideMode
An excellent way to learn more is to look through all of the examples that come packaged with the framework. Open the examples in your browser, then look through the code to find out how things are done. You will find it way easier to learn this way, rather than reading it on paper or a website. Nothing beats experience when it comes to learning something new.
How to select: by ID, by class, via parent, find (OR children OR query OR select? WTF), siblings, ComponentQuery, DOM-query, CSS-query, etc..
Ext.ComponentQuery.query("*") // get all
Ext.ComponentQuery.query("button") // all buttons
Ext.ComponentQuery.query("#myid") // all controls / components myid
Ext.ComponentQuery.query("#myid", rootelement) // all controls / components myid with rootelement
Ext.ComponentQuery.query("#myid,button") // all buttons or controls / components myid
How to manipulate in the tree: create, append, prepend, insert after this sibling, move to that parent, remove, destroy, etc..
Adding button to a View:
Ext.ComponentQuery.query("#viewId")[0].add(new Ext.Button({ text: 'test'}));
There is also insert, remove and so on depending on the control you are querying.
How to manipulate on the screen: show, hide, fade, slide, move up, down, change size, etc..
Ext.ComponentQuery.query("button").forEach(function(button){ button.hide(); }) // hide all buttons
There is also show, disable, enable and so on depending on the control you are querying.
How to identify related to each other: find DOM.Element knowing its Ext.Component, find Ext.Component knowing its DOM.Element, etc..
Finding Ext.Component knowing its Dom.Element is pretty easy, you just take the ID from the DOM element and use Ext.ComponentQuery.query("#id").
There is also Ext.select('#id') for getting the object from an ID.
With the element property you can get the DOM:
var dom = Ext.ComponentQuery.query("button")[0].element.dom // Getting the DOM from the first button
var dom2 = component.element.dom // does also work as long as component is a valid sencha touch component
What is the dependency between them: what happens to the DOM.Element if its Ext.Component is hidden / destroyed / changed / moved, what happens to the Ext.Component if its Ext.Element is hidden / destroyed / changed / moved, etc.
I think, I'm not sure, that if you call .hide for instance there will be some CSS applied to the DOM for example: display: none. Internally they can use some framework like jQuery for that or the old school version document.getElementById('id').css and so one. If you call .show, it may change to display: block or whatever type it was before(this could be saved in the Sencha Touch class).
I don't know what happens if the DOM element gets destroyed. Probably the element too and then the garbage collector has some work to do.
If there are any more questions / something was unclear or not enough, don't hesitate to ask.
An attempt to answer the question myself.
Since there is no TABLE markup support on this website, I put my answer in this shared Spreadsheet. Note the comments on mouse rollover.
It's just a pattern for now. It needs work to get more legible and complete. Feel free to comment, or ask me if you would like to edit it.
I have a custom node type for which I want to have a field that uses a special combobox based on list_text. When one chooses the type list_text it is normally possible to enter a static list of selectable texts, however, I want this list to be dynamic, i.e. based on the results of a db_query. What is the best way to do this using Drupal 7?
A simple example for clarification: A node of this custom type X contains a field that points to another node, so whenever a node of type X is created I want a combobox that contains all other nodes.
(Best solution would be to only display the combobox during node creation, and no longer during edit. But I could also live with it if the combobox was shown during the edit as well.)
I have tried to customize options_select by defining my own data type and implementing hook_options_list accordingly. The combobox was displayed during creation with the correct values, however, I could not save it.. I have no idea what went wrong there, but on the first submit it would change to a different theme, and when I tried again I got an internal server error. Am I on the right track at all with defining a completely new data type for the field? there surely must be a simpler way?
You're right in that you don't need a new datatype. Here's a good tutorial on how to do this. It's not specifically for D7 but I didn't see much that wasn't still applicable. There may be a better way to do it in D7 specifically but I would love to know it too if so :)
The tutorial linked by allegroconmolto sent me on the right way. Thanks for that.
Here's the simpler way of doing it: tutorial
Basically, it is, as I assumed, a common problem and hence a simple solution for it was included in the webform module by now. It provides a hook_webform_select_options_info which can be used to register a callback method. The callback method is then called each time a corresponding option select of a webform is shown, so that you can easily fill it with the results of a dbquery or anything else. Works like a charm and takes next to no time to implement.