Chapter 6: Creating a view from scratch¶
Warning
It is highly recommended that you complete Chapter 3: Fields and Views before starting this chapter. The concepts introduced in Chapter 3, including views and examples, will be essential for understanding the material covered in this chapter.
Let us see how one can create a new view, completely from scratch. In a way, it is not very difficult to do, but there are no really good resources on how to do it. Note that most situations should be solved by either customizing an existing view, or with a client action.
For this exercise, let’s assume that we want to create a gallery
view, which is a view that lets
us represent a set of records with an image field. In our Awesome Tshirt scenario, we would like to
be able to see a set of t-shirts images.
The problem could certainly be solved with a kanban view, but this means that it is not possible to have our normal kanban view and the gallery view in the same action.
Let us make a gallery view. Each gallery view will be defined by an image_field
attribute in its
arch:
<gallery image_field="some_field"/>
To complete the tasks in this chapter, you will need to install the awesome_gallery addon. This addon includes the necessary server files to add a new view.
Goal
The solutions for each exercise of the chapter are hosted on the official Flectra tutorials repository.
1. Make a hello world view¶
First step is to create a JavaScript implementation with a simple component.
Exercise
Create the
gallery_view.js
,gallery_controller.js
andgallery_controller.xml
files instatic/src
.Implement a simple hello world component in
gallery_controller.js
.In
gallery_view.js
, import the controller, create a view object, and register it in the view registry under the namegallery
.Add
gallery
as one of the view type in the orders action.Make sure that you can see your hello world component when switching to the gallery view.
2. Use the Layout component¶
So far, our gallery view does not look like a standard view. Let’s use the Layout
component to
have the standard features like other views.
Exercise
Import the
Layout
component and add it to thecomponents
ofGalleryController
.Update the template to use
Layout
. It needs adisplay
prop, which can be found inprops.display
.
3. Parse the arch¶
For now, our gallery view does not do much. Let’s start by reading the information contained in the arch of the view.
The process of parsing an arch is usually done with a ArchParser
, specific to each view. It
inherits from a generic XMLParser
class.
Example
Here is an example of what an ArchParser might look like:
import { XMLParser } from "@web/core/utils/xml";
export class GraphArchParser extends XMLParser {
parse(arch, fields) {
const result = {};
this.visitXML(arch, (node) => {
...
});
return result;
}
}
Exercise
Create the
ArchParser
class in its own file. It can inherit fromXMLParser
in@web/core/utils/xml
.Use it to read the
image_field
information.Update the
gallery
view code to add it to the props received by the controller.
Note
It is probably a little overkill to do it like that, since we basically only need to read one attribute from the arch, but it is a design that is used by every other flectra views, since it lets us extract some upfront processing out of the controller.
See also
4. Load some data¶
Let us now get some real data.
Exercise
Add a
loadImages(domain) {...}
method to theGalleryController
. It should perform awebSearchRead
call from the orm service to fetch records corresponding to the domain, and useimageField
received in props.Modify the
setup
code to call that method in theonWillStart
andonWillUpdateProps
hooks.Modify the template to display the data inside the default slot of the
Layout
component.
Note
The loading data code will be moved into a proper model in the next exercise.
5. Reorganize code¶
Real views are a little bit more organized. This may be overkill in this example, but it is intended to learn how to structure code in Flectra. Also, this will scale better with changing requirements.
Exercise
Move all the model code in its own
GalleryModel
class.Move all the rendering code in a
GalleryRenderer
component.Adapt the
GalleryController
andgallery_view
to make it work.
6. Display images¶
Exercise
Update the renderer to display images in a nice way, if the field is set. If image_field
is
empty, display an empty box instead.
7. Switch to form view on click¶
Exercise
Update the renderer to react to a click on an image and switch to a form view. You can use the
switchView
function from the action service.
See also
8. Add an optional tooltip¶
It is useful to have some additional information on mouse hover.
Exercise
Update the code to allow an optional additional attribute on the arch:
<gallery image_field="some_field" tooltip_field="some_other_field"/>
On mouse hover, display the content of the tooltip field. It should work if the field is a char field, a number field or a many2one field.
Update the orders gallery view to add the customer as tooltip field.
See also
9. Add pagination¶
Exercise
Let’s add a pager on the control panel and manage all the pagination like in a normal Flectra view. Note that it is surprisingly difficult.
See also
10. Validating views¶
We have a nice and useful view so far. But in real life, we may have issue with users incorrectly
encoding the arch
of their Gallery view: it is currently only an unstructured piece of XML.
Let us add some validation! In Flectra, XML documents can be described with an RN file (Relax NG file), and then validated.
Exercise
Add an RNG file that describes the current grammar:
A mandatory attribute
image_field
.An optional attribute:
tooltip_field
.
Add some code to make sure all views are validated against this RNG file.
While we are at it, let us make sure that
image_field
andtooltip_field
are fields from the current model.
Since validating an RNG file is not trivial, here is a snippet to help:
# -*- coding: utf-8 -*-
import logging
import os
from lxml import etree
from flectra.loglevels import ustr
from flectra.tools import misc, view_validation
_logger = logging.getLogger(__name__)
_viewname_validator = None
@view_validation.validate('viewname')
def schema_viewname(arch, **kwargs):
""" Check the gallery view against its schema
:type arch: etree._Element
"""
global _viewname_validator
if _viewname_validator is None:
with misc.file_open(os.path.join('modulename', 'rng', 'viewname.rng')) as f:
_viewname_validator = etree.RelaxNG(etree.parse(f))
if _viewname_validator.validate(arch):
return True
for error in _viewname_validator.error_log:
_logger.error(ustr(error))
return False