I have a hierarchy of categories, where a category can have a single parent (and you can have multiple levels of children.)
I'm investigating ways to display this information to the user and it seems like a basic vanilla tree layout is the most intuitive way to go. But I'm wondering if anyone can suggest other approaches.
The requirements would be,
1) clearly demonstrate to the user the list's parent / child relationships
2) allow the user to easily move items around (whether by drag and drop or some other method)
3) Assuming you had hierarchal data that had multiple parents, how would that change your choice?
Thanks everyone! - Kevin
Your basic tree control has been a great success for showing hierarchical relations. It’s relatively easy to learn for novices and is now the de facto standard for hierarchies. It is very suitable for editing relations, especially with drag and drop. It is perhaps the only viable choice when the hierarchical depth varies arbitrarily by object (i.e., for any object on the tree, there can be children, grandchildren, great-grand-children, and so on to an indefinite number of “generations.”).
The primary alternative to tree is a window with master-detail panes. In this design, one pane contains parent objects and another contains child objects. Selecting a parent object populates the child pane with its children. You can have grand-child panes and great-grand-child panes as necessary, but master-details generally work best when there is a small fixed number of layers to the hierarchy. Users edit the parent-child relations by drag-and-drop and cut/copy & paste of child objects either within or between windows, similar to using a tree control.
Master-details are usually better than trees for the following cases:
You need to show multiple properties or attributes with each object. For example, for a given Project object, you want to list not only the Employee Number for each Team Member, but also their respective Names, Roles, Titles, Divisions, and photographs. With a master-detail, each pane can be laid out as a table or form allowing you to show a lot about each object. Tree controls often resort to inefficient and confusing Properties dialogs to accomplish this.
You need to subdivide children. For example, for a given Project object, you want to keep its Team Members separate from its Project Stages. With a master-detail, you can have two or more child panes for a single parent pane, with one pane listing the Team Members and one listing the Stages. It’s awkward to keep unrelated child objects separate with a tree control.
You have many-to-many relations, where each child may have multiple parents as well as each parent having multiple children. For example say each Project has multiple Employees (as Team Members) but each Employee may work on multiple Projects. You can have a window with Projects in the parent pane and Team Members in the child pane, or Employees in the parent pane and Project Assignments in the child pane, or you can have both windows. Tree controls may confuse users when there are many-to-many relations because users don’t expect the same child to be under more than one parent.
TreeGX is a sweet way to display hierarchical data in a different fashion from the standard tree - link is here.
I use the component to present search results and while it is NOT free it is worth the money if you want to present something unique.
You can put some visual flow chart style design to make it more engaging. How far you want to go is totally up to you. This will help you with multiple parents.
Your question treats your design problem as if it is an abstract thing. Unfortunately, it's not that simple - if only there was one perfect solution!
UI Design is highly contextualised. You have to think about the user group (i.e. their needs, goals and expectations) and the type of activity you are trying to support (i.e. what exactly is the user doing when they browse this tree? What's their goal? Are they going to use your app daily or once a year? etc). What works in your context may not work well elsewhere.
People are always disappointed when told "go build a quick prototype and test it on a sample of your end users". It involves further work and it outside a typcial developer's comfort zone. However, it is the only way to be sure that your UI is right for your given context.
Related
I'm wondering if their is a tutorial on how to convert an admin UI into Ember components? What are the best practices? For example, the following UI framework: http://egemem.com/theme/kode/v1.1/blank.html
Has a main navigation, two sidebar menus, a content body and a footer. What would the best approach be to converting this into components? My initial thoughts, with very little Ember experience and based on the scattering of documents I've been able to find, I get the sense that creating unique components for everything would be the best approach. By everything I mean, everything that is unique. For example, if we take the navigation bar, there would be a parent component for the navigation as a whole and then child components for the sidebar collapse/expand buttons, the search, the drop down menus, notification indicator, etc. There would also be additional parent components for the right hand sidebar, left hand sidebar, and footer.
Looking at one of the sidebars, for example the left one, could that be one component or would child components be required here as well?
The right hand sidebar is more complex with tabs. In this example, would it make sense to break this sidebar into child components for the 3 different tabs? Would you want to go as far as a unique component for different elements of the tabs themselves. For example, each notification type would be a component?
Thank you in advance for your assistance send I look forward to understanding how best to handle this type of scenario.
Cheers,
Dan
Yes, your idea makes sense. It is a good practice to create components (or handlebars) for everything that repeats several times. I would not create different components for different tabs if they are not re-used.
Do not forget to not re-invent wheel. There are a lot of available components, take a look at Ember Observer or other similar resources.
Components are great but some the things you mentioned, like sidebars, might make more sense as nested routes, depending on what's in the sidebars.
Rock 'n Roll with Ember is a fantastic book that takes you all the way through the process of building an Ember application. It's the book I always recommend to people just getting started with the framework. http://balinterdi.com/rock-and-roll-with-emberjs/
I may be bordering on a discussion type question here so I apologise if the question is not specific enough.
I would like to know if I my current application design is inherently weak/flawed. My background is C so I am not using clever c++ patterns to their fullest extent, of this I am sure.
My application is similar to a 3D modelling package, without geometry creation (e.g setting up animations using existing models). The user imports a geometry and can set various parameters on pre existing geometry, and there are time dependent values that relate to the whole system. The output is a text file to be processed by another application.
I am using a QTreeview to render a QStandardItemModel. I simply store pointers to my core classes in the model's items. These have specific UI for each class type, and are all descended from a common base class. They all have a QWidget which is their "mainwidget"
When the user clicks on part of the treeview, the stored class is retrieved and its mainwidget is displayed on a pane on the UI. So - treeview on the left, pane to the right with the current item's contents, and a 3D view showing the geometry.
Most of my data is stored in the classes UI elements themselves; I don't have a central database which stores anything, and when it's time to save the project, I traverse the tree and let every item write itself to a QSettings file. This feels quite naive but it does work, and the reverse happens on project load. The project class generates new classes based on the type information in the settings file and they then read the contents out of the file themselves.
Similarly when writing the output file, each item knows how to write itself and does so. Where other classes can influence the output of others (for example, start and end times), higher level classes process the children and will set start and end times based on the order and duration of each child.
Should I be storing more data in the QStandardItemModel itself, or defining my own model perhaps? Does it sound like I have set myself up for future problems?
At the moment I have modified this system a couple of times to provide customised applications, but I am about to try and make it more generic. I welcome suggestions for improving my design. Go easy, please!
You should try to avoid creating god objects. Split your tasks and duties into smaller chunks. It makes it much easier to maintain and also much easier to extend if you need to.
Your specific use-case would benefit a lot from a more complete use of the Model-View-Controller pattern.
What doesn't make sense in your design is that your data objects hold a UI element. Since only one item can be shown in the right pane, this seems like a waste of resources. It makes more sense to have a single object that then gets passed a data object to display.
What I suggest for your program is the following:
Splitting your data into classes that only have functions for reporting and modifying values. There should be no knowledge of how to display data or store to a file.
Create separate class that handles the reading and writing from a file. If your model is very simple, you could just use single functions to do this using the method shown in the documentation for QDataStream or QTextStream.
Use your QTreeView and QStandardItemModel as Adaptor class between your data objects and the left pannel.
Create a controller class that gets informed by the QTreeView if data needs to be displayed in the right panel. The controller will then retrieve the data item and pass it to the right panel in order to be displayed.
The right panel should act like another View class with the sole responsibility of graphically displaying the data passed in from the controller class.
One advantage of doing it this way is that, if there are different categories of data that get displayed differently in the right panel, the controller could examine the selected data item, determine what the category is, create a view widget to put in the right panel, and then pass it the data to display.
This pattern is open-ended as far as extendability is concerned because you do not need to change your data classes if you need a new display, you merely need to create a new right-panel widget, and then teach your controller class how to determine when the new view should be used.
Another advantage of this pattern is that you only ever need to have a single widget created to display data in your right panel. If you change your selected item, you can just pass it to the view class that already exists and get it to refresh its display with the newly selected data. You only need to distroy the right-panel view widget if a different category of data object is selected and its data needs to be drawn in a different way. The controller class can determine whether a right-panel view widget can be re-used or whether it needs to be swapped out for a different widget.
I have an application scheme implemented in Ember that basically follows this layout:
The concept is that the user can interact with features on the Map View (which is always present) and basic navigation occurs between various views in the Parent View and an arbitrary stack of Sub Views. The user can create new features on the map, edit existing ones etc.
The URL for a particular feature could be /features/123/edit
Since input into my interaction panels is very much dependent on interaction with the Map View (drawing a polygon, placing a marker etc.) my controllers for these views are setup to "need" the Map Controller. When a particular panel view is present interaction with the map should affect the panels in various ways.
My question is - how does one scale such tight controller coupling? I essentially need to switch between different Map modes based on which panel is currently active. I also, I believe, need to observe events on the map and act upon such events depending on the current active panel.
I setup a proof of concept where a certain Sub View Controller observes certain properties of the Map Controller (with for example .observes("controllers.map.activecoords") however, such an observer will continue to trigger even after the user has navigated away from the particular Sub view (i.e. as soon as the controller has been initialised). Must I setup and tear down such observers manually (i.e. using addObserver) when entering and leaving the route? Is this the right pattern? I've gotten the impression that requires that I manually remove all such observers during transitions to avoid unexpected behaviour and memory leaks.
Perhaps I'm going about this completely the wrong way? Are there any others patterns that fits my use case with an always present map with different states and intercommunication with interaction panels?
Perhaps the architecture of your application shouldn't be connecting controllers, but rather ask yourself "What is the model here, really?"
In each case, I think the model is your map, or at least its "contents". The features are really decorating the interaction with your central model, which is the map, underlying it all.
So really you have a single model here. You effectively have a map resource, and many feature routes on that resource, viewed from the URL/API.
The question is now not so much "how to manage a dependency hierarchy between controllers?" as "how do I manage a view and a subview on the same model?" which is answered quite simply in the standard ember nested route. Your outer view is always present and it has an outlet which is where your feature goes. How it's rendered is the inverse of how the standard nested route is rendered, but nevertheless it's the same pattern.
So, the TL;DR answer is... go through your model and the routes... use them to talk about your common data: the model is, afterall, your data, and the controllers and views are simply augmenting and enabling the user experience, presentation and interaction of them.
Most of these sorts of architectural problems can be resolved by moving the data up and down the hierarchy (template view / component / controller / route / model) until you find a place which is low enough to still be accessible to objects that need access to it, yet high enough that it makes sense by not being tightly bound with too many things, but still is in the right spot and "feels right".
If it's too high, you'll tend to be doing the wrong kind of work with your objects (ie controllers should not be mucking with view mechanics, models shouldn't really have presentation stuff in them, etc.
If it's too low, you'll tend to be doing too much work with the framework and you'll tend to be repeating yourself a lot... ie controllers will be doing a lot of work to get the data they need, for example.
I have an Object (Option) that is nested three levels deep (Items->Options->Option). When an Option is selected, all three objects will change their display (Option will be highlighted, other Options will be de-emphasised, and the Items will be rearranged).
What is the preferred way to handle this series of actions?
Ember.js - Propagate event up the controller/router chain - In this example each object responds to the action then tells the action to continue propagating. Makes sense, but I get the impression that this may be an unorthodox approach to what must be a common problem. Is this a good option?
You have three choices:
1. Propagate up the controller hierarchy.
This is the easiest and best option when the objects are actually in a hierarchy or tree on the model side, because then each object's controller has an explicit reference to the parent object's controller.
2. Propagate up the route hierarchy
This is the best option when the view hierarchy does not necessarily correspond to a tree structure in the models, but is semantic. If you think the semantic arrangement of the related objects is prone to change in the future, this a better option. However, you are still assuming that there IS a hierarchy
3. Let the first handler be the topmost route that "knows" how the objects are related,
and that handler sends events to the necessary controllers.
This option is best when the relationship between the objects in a particular set of views is semantic and not necessarily hierarchical and you think the routes/views might move around during the development of the app. The best example of such situations are "negative" events -- for example, deselect
You can always mix these strategies. I've found that refactoring is easier if events tend to go up to a route and back down to necessary controllers rather than having a lot of needs in my controllers.
Let's say there exists a presentational component in a project that renders an unordered list (called ListRenderer, perhaps.) We have a couple options of supplying data to any given ListRenderer on a page:
Have a TreeList (or TreeListEx) field on the content item, and have ListRenderer read from it.
Supply a DataSource (or other Parameter) to the ListRenderer via the presentation details.
I usually avoid #1 in my projects because it binds Sublayouts to templates, which gets quite messy. If you go down that path, eventually you'll have fields to support every potential sublayout in your project.
So my solutions tend toward option #2, which gets rid of that problem. It does, however, come with its own bag of questions. Where do I put these various "Lists" for a given ListRenderer to use? To maximize reuse and sharing, I usually create a components directory near the site root that contains all these types of things, if I predict the Lists will be shared. This seems less findable and harder to use for the content author, who suddenly have no idea where the source for their ListRenderer is unless they know how to crack open the presentation details (which is slightly advanced for my average user).
If I feel like Lists won't be shared, and are very specific to the page, I'll put them directly underneath the item in question. This has a tendency to muddle up the content tree, though, and any dynamically generated navigation sublayout then has to check for whether or not an item is an actual page before it generates the link to it. The more I work in Sitecore, the less I use this approach, but it seems easier for the content author. There is much easier access to information when you use this approach.
Is there any industry-accepted way of approaching this problem? It happens in projects all the time, and in my head I struggle to balance technical and content authorship concerns in situations like these.
Great question. I've used all the techniques you mentioned, depending on the audience and specifics of the project. The problem is that, as with all things Sitecore, they are all valid ways of achieving the same goal and you will struggle to find one answer that will work in every situation.
I almost always use #2 as well, but some content author retraining maybe necessary and make sure you add in restrictions to what the content author is able to select as a target. I have (within the same project) structured the items near the root (in a shared content folder) and under the item in question, depending on what I felt would provide the best context.
Also, if other child pages would exist below the item as well as the list items, then I would put the list items in a separate folder (with a common "list items" icon") and re-order it to be the first item for separation and clarity.
If you want to use any kind of personalization and DMS then you will need the ability to switch out the datasource anyway so you shouldn't hard code locations.
You might also (if you have not already) want to consider using:
Convert Data Source Paths to IDs Using the Sitecore ASP.NET CMS
- Useful if you need to restructure your content at a later date
Queryable Datasource Locations
- Useful for multi-site situations when you need to make clones, or setting as the default datasource value in Standard Values when the lists are directly below the item but gives you the flexibility to change it.
I prefer using querable datasources personally, I find the xpath syntax more logical.
As Mark has commented, there is no real industry standard.
I feel like this is something that needs improvement.
Especially when you are using the DataSource option, things become less transparent to the editors and as the size of the site grows, so does the complexity.
All I can tell you is how I would do it, which is most likely much like how you are doing it.
1) For overview pages like news, events and faq items, I will put the items underneath the overview item and use the NewsMover shared source module to auto-create a hierarchy.
2) I will create a Global site that contains items that are shared across sites or pages. DataSource items for components will be put in here.
3) For components that are present on the standard values, I will add a list field to the template (for example, when you display related items on a content page)
Most often it's a logical choice and sometimes it's just a matter of taste.
I'd like to add that I've written a blog post on how to have datasource items created automatically for components that are set on standard values. That might help you if you are using those.
Edit:
"I usually avoid #1 in my projects because it binds Sublayouts to templates, which gets quite messy. If you go down that path, eventually you'll have fields to support every potential sublayout in your project."
Today I've blogged about a method of hiding fields and sections in the content editor if there is no sublayout set on the item that requires those fields, which helps to prevent the mess of having a lot of unused fields on your items.