Creating a detail info screen
What you will learn
This lesson will explain :
- How to create
Module
, - How to route with parameters,
- How to implement
Deeplink
, - How to focus a specific child,
- How to implement animations between screens.
The final result :
Introducing modules
What’s Module in Dana’s perspective ?
A module allows you to separate a complete feature from your application. You can add or remove a module in your application according to the profile of your application in the configuration file.
What is doable in module ?
In a module you can :
- declare and register new routes
- add/overwrite style, i18n, configuration
- add behavior to a component
If you check in your current tutorial project, a folder named modules
has been created. In this folder you can create as many modules as you need. Here one is already created named ‘fip’ (Full Info Page). The name is defined in the package.json, inside the ‘fip’ folder.
In the fip
module, you will find :
modules/fip/package.json
: definition of the module in package.json file.modules/fip/scripts/FipModule.js
: [moduleName]Module.js similar to Application and inherits fromAbstractModule
.modules/fip/scripts/FipRoutes.js
: [moduleName]Router.js similar to AppRoutes and inherits from$Routes
.modules/fip/scripts/ui/screens/*
: specific or override screens of your module.modules/fip/scripts/ui/views/*
: specific or override views of your module.
Add module in your application
This module use theme values, they need to be added in statics of AppTheme
:
TRANSPARENT: "#00000000",
H1_FONT_SIZE: 42,
H2_FONT_SIZE: 35,
DEFAULT_FONT_SIZE: 20,
SCREEN_HORIZONTAL_MARGIN: 50,
SCREEN_VERTICAL_MARGIN: 30,
///////////////////////////////
// FIP
///////////////////////////////
FIP_IMAGE_WIDTH: 1422,
FIP_IMAGE_HEIGHT: 800,
IMAGE_RATIO: 16 / 9
To add a module in your application, you just have added “modules” in your profile, which is an array of module name.
Here we want to add the module fip
:
"base-css": {
"base": {
"name": "Css",
"vendors": [
"@dana/renderer-css",
"@dana/vendor-components",
"customBE"
],
"modules": [
"fip"
]
}
},
"base-lightning": {
"base": {
"name": "Lightning HTML5",
"vendors": [
"@dana/renderer-lightning-html5",
"@dana/vendor-components",
"customBE"
],
"modules": [
"fip"
]
}
},
Congrats !! The module fip
is available in your application, but not used yet. You will need to route to this module.
Routing with parameters
The module is properly loaded but not use yet. The module share one route defined in FipRouter.js
named fipContent
displaying the $FipContentScreen
.
fipContent: function (data) {
return $FipContentScreen.display(data);
}
As you can see, the route fipContent
require data
to be displayed. The FipContentScreen
needs the data to display the content information.
In CatalogScreen.js
you will route to the FipContentScreen
and add in parameters of route the needed datas object.
To display the information of a content, this screen needs to get the datas of the selected content. To send the selected content to the screen, the options object will allow you to send datas the screen requires to be displayed properly.
/**
* @override
*/
ok: function (key) {
if (this.scrollView.isFocused === true) {
const data = this.scrollView.getItemView().getItem();
const options = {
contentId: data.id
};
return this.route("fipContent", options);
}
}
Then on screen side, if you open the FipContentScreen.js
you will get the given data in parameter of the prepateData
method.
So by using the VodService
and the contentId
the screen are able to get datas.
/**
* Prepare screen data: get the business data to feed the views
* View should always be filled with business model(s).
*
* It must return a Object.
*
* @param {Object} [context] The context shared by the screens during display
* @param {string} [context.contentId] The id of the content to display information
* @returns {Promise<Object,Error>} returns a promise resolved with the data
*/
prepareData: function (context) {
return this.vodService.getContentDetails(context.contentId);
},
The value returned in this method will be used to create the data value of the screen, and can be used in connectData
as shown below :
/**
* Connect the data prepared by {@link prepareData} to the views.
* Use the data property, which is the return value of {@link prepareData}.
*
* @param {Object} [context] The context shared by the screens during display
*/
connectData: function (context) {
this.contentInfo.data = this.data;
this.image.url = this.data.imageUrl;
},
Then if you want to return to the previous screen from FipContentScreen
, you can override the back
method behavior in the screen file :
/**
* @override
*/
back: function (key) {
return this.routeToPrevious();
},
Now, you can reach the full information page by pressing OK
on any item of the rails and back to the catalog to navigate and select another content.
Deeplink
Deeplink overview
In some cases, you may want to display directly the information page without launching the app or search the content and click on it to display the information.
Dana propose a mechanism called deeplink, making this behavior possible on each platform .
Deeplink on browser platform
On browser, Dana uses the URL mechanism to handle the deeplink.
First, the screen FipContentScreen
need contentId
parameter to get datas and fill their views with them.
http://localhost:9000/template-lightning.html?contentId=1115
Then, Dana need to know which screen you want to be displayed.
http://localhost:9000/template-lightning.html?contentId=1115#fipContent
After this url built, you can use this link in your browser, and you will reach directly the FipContentScreen
whitout route by the catalog screen.
Deeplink and history management
Previously, when the user display the information screen, he used the catalog screen to select a content. So when the user press Back, the RouterManager
can display the previous route.
Caution
In a deeplink case, there is no previous route cause, the information screen is the first route and the user is blocked.
To fix this behavior, you can override the back
method of FipContentScreen
to handle the route when there is no previous route.
/**
* @override
*/
back: function (key) {
if (this.routerManager.previousRouteName == null) {
return this.route("catalog", {
animations: {
show: "catalogEnter",
hide: "fipContentExit"
}
});
} else {
return this.routeToPrevious({
animations: {
show: "catalogEnter",
hide: "fipContentExit"
}
});
}
},
This way the user isn’t blocked. Other way to fix this, is to display the menu on this screen allowing the user to reach the catalog screen.
Focusing a specific child in a screen
By default, Dana focus the first focusable view in the screen’s children. If you want to override this behavior a method is at your disposal _getChildToFocus
.
In FipContentScreen
, the first view in children is contentInfo
. So as it is, this is the first focused view. This view is a simple view just displaying data, not a focusable view.
To modify this, you just have to return the view you want to be focused like below :
/**
* @override
*/
_getChildToFocus: function () {
return this.playButton;
},
Now, the play button is the focused view when displaying the screen.
Animations between screens
The mechanism of routing between screen allow you to defined animations when you show or hide a screen. This mechanism is based on the route parameters.
Caution
The animations are available only on views.
Create animation
In FipContentScreen.js
add keyword animations
which is an object of {string, function}
.
string
: the key defining the name of the animationfunction
: the function implementing the full animation
First, create the animations for FipContentScreen
:
- The first one will be used when the screen will be shown
fipContentEnter
. - The second one will be used when the screen will be hidden
fipContentExit
.
animations: {
fipContentEnter: function () {
let screenAnim = this.addPropertyAnimation("x", {
delay: 0,
duration: 250,
from: 100,
to: $Theme.FULL_SCREEN_WIDTH + 100
});
screenAnim.start();
return [
screenAnim
];
},
fipContentExit: function () {
let screenAnim = this.addPropertyAnimation("x", {
delay: 0,
duration: 250,
from: $Theme.FULL_SCREEN_WIDTH + 100,
to: 100
});
screenAnim.start();
return [
screenAnim
];
}
},
Secondly, create the animations for CatalogScreen
- The first one will be used when the screen will be shown
catalogEnter
. - The second one will be used when the screen will be hidden
catalogExit
.
animations: {
catalogEnter: function () {
let screenAnim = this.addPropertyAnimation("x", {
delay: 0,
duration: 250,
from: -($Theme.FULL_SCREEN_WIDTH + 100),
to: 100
});
screenAnim.start();
return [
screenAnim
];
},
catalogExit: function () {
let screenAnim = this.addPropertyAnimation("x", {
delay: 0,
duration: 250,
from: 100,
to: -($Theme.FULL_SCREEN_WIDTH + 100)
});
screenAnim.start();
return [
screenAnim
];
}
}
Use animation between screens
Configure the animation when the user display the FipContentScreen
from CatalogScreen
. Remember, you can send data to a screen with the route
method. You can to use this mechanism to define the animations in option
parameter.
When you route to another screen you can define the animations
property in options, this property handle show
and hide
animations. The value of those properties are the name of the animation.
The show
animation will be applied on the screen that will be displayed.
The hide
animation will be applied on the screen that will be hidden.
In our case, you want to apply an animation between CatalogScreen
and FipContentScreen
, the screen that will be shown is the FipContentScreen
so, you can define as show animation the fipContentEnter
animation. Then the screen that will be hidden is the CatalogScreen
so, you can define as hide animation the catalogExit
animation.
Here the result :
/**
* @override
*/
ok: function (key) {
if (this.scrollView.isFocused === true) {
const data = this.scrollView.getItemView().getItem();
const options = {
contentId: data.id,
animations: {
show: "fipContentEnter",
hide: "catalogExit"
}
};
return this.route("fipContent", options);
}
},
Then configure the animation when the user want to return to the CatalogScreen
from FipContentScreen
.
In this case, you want to apply an animation between FipContentScreen
and CatalogScreen
, the screen that will be shown is the CatalogScreen
so, you can define as show animation the catalogEnter
animation. Then the screen that will be hidden is the FipContentScreen
so, you can define as hide animation the fipContentExit
animation.
Here the result :
/**
* @override
*/
back: function (key) {
return this.routeToPrevious({
animations: {
show: "catalogEnter",
hide: "fipContentExit"
}
});
},
Summary
In this lesson you have learned :
- How to create and use a module,
- How to send data to another screen by routing api,
- How to use DeepLink feature,
- How to use animation between screens