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.
Related
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.
I'm building a class (sorry - Agent) that will work with a set of Tank objects (Fluid Library) - doing things like monitoring individual levels or total level of all tanks, reporting on levels and initiating actions based on levels - things of that nature. For argument's sake let's call it a "TankMonitor" agent.
Ideally I'd like to be able to define a Parameter in my "TankMonitor" agent that allows me to define the tanks of interest when I place a TankMonitor in main. I have tried to define the type of the parameter as Other - ArrayList<Tank> however I don't know how to set up the next step to allow me to populate the ArrayList of Tanks when I put an instance of this agent in main. My preference would be to have a list type control to populate the ArrayList - much like the way the AnyLogic Seize block allows you to specify multiple resource pools to choose from.
Has anyone attempted this before and been successful?
This is possible as follows:
Change the type to "Other" and then 'Tank[]' , i.e. an Array of Tanks
Change the control type to "one-dimensional array"
Example below. Now you have the same UI to pre-define tanks at design time for your agent instance.
In addition to Benjamin's perfect answer, I'd just add the manual workaround, which is not needed here but can be useful when the parameter in question has a more complicated structure than covered by the pre-made controls, say a list of lists, a map, or similar.
In such a case, the Control Type is still Text, and populating it in an instance happens by pointing it to a new object of the parameter's type. E.g. for an ArrayList<Tank> parameter, you might instantiate a new ArrayList object, which you fill with a list of objects like so:
new ArrayList<Tank>(Arrays.asList(tankA, tankB))
In the Java code, whatever is written into that text box will end up on the right side of a parameter assignment statement in the embedded Agent instance's auto-generated parameter setup function. Therefore, multi-statement code won't work in this spot. Instead, if the process of building the parameter value doesn't fit neatly into a single expression, you can hide the code in a function which returns the desired object, and call that from the parameter's text box.
I am building simple crud for an entity. Initial state is read on particular entity(key) using view>form.bindElement('/entity(key)').
when I click on new button I clear the form and when the cancel button is clicked during the new/create process(without performing the save), how to go back to the previous entity. Is there some place ui5 stores, the previous entity or should I have some variable and assign it to the controller.previousEntity = oldsPath?
what are the different members in the oModel,it start with
a(aBindings)
b(bUseBatch)
m(mContexts)
o(oHeaders)
p(pCallAsync)
s(sPathUrl).
Is there a naming convention in these?
From what I can see, there are following things you need to notice and work upon.
Its generally not a good idea if you use the same form to display and to create/update also. A simpler approach would be to
use a new popover to show the form for create and in that case, the view binding would not be changed when you cancel the operation.
However, if you still want to use the same form, yes you would have to bind the view/form again on cancel operation. You can have a variable declared in the Component.js to store the path for you. In UI5, the model captures the current state to ensure the back the binding concept by default.
You can check all properties and their definitions here: oData Model
Yes, there is a naming convention followed here.
a - Array, s-String, b- Boolean etc.
Read more about Hungarian notations for naming conventions
The previous entity is still there in the cache (ODataModel.oData), but you'll need to re-bind it. For that purpose, as you have written, you'll need to store the path to the entity yourself. Once you bind the control, I don't think the previous binding context is stored somewhere (why should it).
I would like to append a Binding node to another Binding node without re-rendering the parent node.
Is there a specific way how Binding.scala would handle this?
Bindings can be nested and composed, so in general it's not something you need to think about. A Binding[T] represents an object that is dynamically bound and will be recomputed when any upstream Binding's value changes.
Your question is a bit ambiguous so you may want to clarify or add a code example, but there is nothing extra you need to do to accomplish your goal. Look at the examples and also this section of the README:
https://github.com/ThoughtWorksInc/Binding.scala/blob/11.0.x/README.md#precise-data-binding
Also, I made a quick example of what I'm talking about here:
https://scalafiddle.io/sf/XZgtwHM/1
If you open up your browser console, you'll see that the method that renders out the parent node is only called the first time, but if you click the button more child elements will be appended without the parent node being affected. Inspect the HTML and pay attention to the id of the parent div, it is set up to increment the ID each time it gets rendered, and the id remains as "parent_1" the whole time.
In Flux pattern, is it ok for a store to declare multiple events for a view to listen to? E.g. listChanged, selectedListItemChanged, etc. At first glance it seems legit to me (either this or passing additional parameter in a change event) as it doesn't break the flow and just adds few down arrows from store to view.
I've ommited "React" on purpose, because I'm looking for a generic pattern, not bound to concrete rendering library. And having one stateChanged event makes rendering process very complex without ReactJs magic.