OpenSAP Ui51 Week 3 Transcript
OpenSAP Ui51 Week 3 Transcript
00:00:09 Hello and welcome to Week 3 Unit 1 of our openSAP course "Developing Web Apps with
SAPUI5".My name is Thomas Marz and I am Product Owner in SAPUI5.
00:00:22 This week we will build a completely new application.In the last two weeks you have been
practicing the basic development paradigms of SAPUI5.
00:00:37 And now we are ready to build a completely new application.As we do this in the real world, we
don't start from nothing, we start with an application template
00:00:48 that gives you a well-defined structure along our best practices.That is what we will do today,
creating the application with the template,
00:00:58 and then throughout the rest of the week there will be five more exercises where you add more
features to the application, along with developing SAPUI5.
00:01:11 Then some words on the steps: basically, at first, we extend the ES4 destination that was
configured in Week 0,
00:01:23 to make it ready for SAP Web IDE.Then we will create a new project with the help of the
worklist template.
00:01:35 Then we will run the application in your local workspace.And last but not least, we will run the
application on the SAP HANA Cloud Platform.
00:01:49 So those are the four steps I want to do with you So we'll start in SAP HANA Cloud Platform
Cockpit.
00:02:06 And here, on the left-hand side, you'll find the destinations.Here, you'll find the destination ES4
that we set up in Week 0.
00:02:20 You press on the destination and see the details below.There's an "Edit" button down there
that we press.
00:02:31 Now we have to add additional properties to this destination.I'll choose "New Property",
00:02:40 and I'll choose "WebIDEEnabled".I'll set this one to "true".
00:02:48 I'll add an additional property, which is "WebIDESystem", and I'll give it the same name as the
destination.Last but not least, there's the "usage", which has to be set to "odata_gen".
00:03:11 Okay, so those are the three properties, and I can now save the destination.Now the system
tells me that it might take a while for the changes to take effect.
00:03:24 Important for you – if you have a Web IDE up and running, you should refresh it now, so the
changes can take effect.Okay, now in SAP Web IDE, I'll open the "File" menu, and I'll choose
"New", then "Project from Template".
00:03:51 Then the first screen of the Wizard opens up, where we have to select the template we want to
work with.And you have a bunch of options here, there are different templates.
00:04:01 The one we are using in this course is the SAP Fiori Worklist Application.So I'll press on this
tile, and on the right-hand side I already get a preview of this application, let's open this up.
00:04:17 We see here that this is a very basic application that shows a set of objects in this table
here.We have two columns – one for the name of this object and one for a numerical attribute.
00:04:33 You can also search the list of objects and navigate to their details, indicated by this little arrow
here.
00:04:47 We call this the design pattern worklist application, in the Fiori design, and this is what we
choose.After choosing the template, I'll press the "Next" button.
1
00:05:00 On the next screen, we have to name our project, and I've called it "ManageProducts".That
should be the name of our application.
00:05:14 I'll press "Next" to go to the next screen... "Data Connection".As we have extended the
destination before, we can now access it from this screen by choosing "Service URL" as
source,
00:05:29 and now we see the "ES4 Demo System" here.Now we are just pointing to a system, but we
have to specify the URL to the service,
00:05:41 and now I'll enter this URL into the field, it's "sap/opu/odata/IWBEP/GWSAMPLE_BASIC".To
check we've done this properly, we hit the "Run" button.
00:06:08 Now on the right-hand side we see that the service, and the metadata, could be read.If we see
this list of objects on the right-hand side, the URL is good.
00:06:21 And with that, I can continue to the next step.I have to specify some more data about my
application.
00:06:32 First of all, the title – it's called "ManageProducts", then the namespace – this one is
"opensap.manageproducts".
00:06:47 I'll skip the description for now, it's an optional property.But the next one is very important, it's
for SAP Fiori launchpad.
00:06:58 We now have to decide whether to let this application stand alone, or enable it to run in the
SAP Fiori launchpad.
00:07:08 For the content of this course, we choose standalone applications and achieve this by setting
the option to "Exclude".The way of configuring this will actually change in the later version of
the template.
00:07:22 In future you will find this option under "Application Settings" as "Type".Okay, what else? Data
binding.
00:07:34 Out of the box we will bind the UI elements, the UI controls, to the data of the service, and this
is specified here.First of all I have to say which entities should be used as objects and I choose
the product set,
00:07:55 so I will take the products of this service to be displayed in the table.The next one has already
been filled out – that's the key field of the service.
00:08:05 Then comes the object title, and I set this to "ProductID".Looking at this picture, we can see
what's behind: the title in the first column,
00:08:23 then the numerical attribute in the second column, which I'll set to "Price", and I'll use
"CurrencyCode" as the unit of measure.
00:08:39 So that all looks fine, I can now hit the "Finish" button of the Wizard, and with that, the
generation of the application code is triggered.
00:08:53 You'll see you have a folder called "ManageProducts" in your workspace.If I open this up, it all
looks familiar – like what you've been doing in the last two weeks.
00:09:04 Here we see an index.html file to run up your application, and a Component.js, together with
the manifest.json describing it.
00:09:14 We see "view", "model", and "controller" folders, and an "i18n" folder containing a bunch of
properties out of the box,
00:09:26 all that has been generated by the template.There's one new folder here, "localService", for
running the application with "mock data" – I'll explain what that is shortly.
00:09:42 Okay, so now let's run this application.I'll choose the folder "ManageProducts", and I'll open
the "Run" menu.
00:09:55 Here we have different options for running the application, I'll choose the first one, "App".You
see now that the application opens up in a new browser tab.
00:10:08 It has the title we specified, "Manage Products", and it's actually displaying products from our
gateway service.So here's a set of products.
00:10:20 They are not all loaded automatically at the beginning, but if you scroll down, further products
are being loaded.In the first column I see the product ID, in the last column I see the price.
00:10:35 I can search the products, now I only see products which contain a "7".If I want more details, I
can click on one of those table rows.
00:10:46 Navigation now takes place, and you see a subscreen with the product details.This one is
quite empty, so the template doesn't do much here because all the applications differ in terms
of details,
00:11:00 and it's up to you to fill this with life.All right, so much for that.
00:11:10 One important thing to mention: we are now running the application against a real service with
real data.If you have a slow network connection, or no network connection at all, you can also
run the application with "mock data".
00:11:29 This means the data is not coming from a real system, instead it's generated on the client for
testing purposes.To run the application with mock data, I open the "Run" menu,
00:11:46 and here you will find an entry called "App (Mock Server)".This is an old version of the
template, which is why it looks slightly different,
00:11:57 but in the template you will be using in the course, you will find an option here called "App
(Mock Server)".When running this – ignore what I've just done – you will now see the
application open up again.
00:12:13 But this time, you can see some product IDs, currencies, and currency codes randomly
generated by the mock server.This is a feature of SAPUI5 that is included, and you can use
this by running the application in the right mode.
00:12:36 Okay, so much for running the application from your local workspace.Now it's time to deploy
the application to the SAP HANA Cloud Platform.
00:12:48 I do this by choosing "ManageProducts", opening the context menu, choosing "Deploy" and
"Deploy to SAP HANA Cloud Platform".
00:13:04 I now have to enter my password... and hit the "Login" button.Then on the next screen you see
some more input, leave all of this as it is.
00:13:26 Just observe that the first version of the application is given, which is "1.0.0".And now I hit the
"Deploy" button...
00:13:44 Okay, the application has now been successfully deployed.Here's a link called "Open the
active version of the application" – I'll press this link.
00:13:56 A new browser tab opens up and I see exactly the same application as before, but this time it's
coming from the cloud.
00:14:07 You could give this URL to other people who have the appropriate rights to launch the
application in the cloud.It's no longer local to your workspace, it's in the cloud.
00:14:19 It's convenient at this stage to bookmark the application. I'll put this on the "bookmarks"
bar.Whenever you want to run the application, you can easily do so by pressing the link up
here.
00:14:35 In case you forget to make a bookmark for your application and can't find it, I'll show you how
to find it.You would go to the HANA Cloud Platform Cockpit,
00:14:54 and here on the left-hand side you have HTML5 Applications.This is where you find your
deployed application, it's called "manageproducts".
00:15:05 When going to the details of this application, you see some information and the application so
from this one you can also run the application.
00:15:21 I'll close this window now.I want to show you what happens on the next deployment, so I'll do
the same thing again,
00:15:33 and choose "Deploy Application to SAP HANA Cloud Platform".And I want you to note that on
this screen the application already has the status "Started" with this very first version.
00:15:51 Now, on the second deployment, the version number has been increased.So whenever you
deploy the version, a new version number is generated, and the new version is activated.
00:16:06 All right, then we must do one last thing.Here you see a folder called "dist", which is the
abbreviation for "distribution".
00:16:17 This folder contains a version of the application that has been optimized for performance.This
is done automatically by SAP Web IDE on deployment.
00:16:28 The performance-optimized version is generated to the distribution folder and is then
deployed.Never do anything in these files, they are not for you, they are generated
automatically by SAP Web IDE.
00:16:44 So whenever you code something, do it in these folders.All right, that was it.
00:16:51 With that we've made a start, we've built a new application from a template, we haven't coded
anything yet.And now through the remaining units of this week, you will fill this application with
life. Have
Week3 Unit 2
00:00:10 Hello and welcome to Week 3 Unit 2 of our openSAP course "Developing Web Apps with
SAPUI5".My name is Thomas and in this unit we will define a responsive table.
00:00:26 In the previous unit of this week, we created a new application with the help of the worklist
template.This application is pretty empty so far, and we'll now start adding content to it.
00:00:41 As a first exercise, we'll add two more columns to the table, displaying information about the
product's supplier.We'll also display the name of the product, because this is useful to have in
conjunction with the product ID.
00:01:01 We will also define a responsive behavior for the two new columns, because if you want to
display this table on a small screen, there's just not enough space,
00:01:12 and we need to handle this somehow.You get a preview for this here and you see that neither
of the new columns is being shown on the phone,
00:01:23 but one of the columns is shown in place, as the "popin".This is a good time to once again
advertise the responsiveness of the SAPUI5 solution, which is one of the key capabilities.
00:01:40 SAPUI5 applications can run on both desktop browsers and mobile devices, and we have
means to cater for the different screen sizes.
00:01:56 So much for advertisement, let's write some code.This is the application we created previously.
00:02:09 Let's run the application...Okay, we see that currently only the ID of the product is displayed –
both in the table and on the detail screen.
00:02:29 We will now add the name in addition. To achieve this, I first open "Worklist.view.xml".Let's
understand what we have in here. Here's the "Table" control.
00:02:46 And here are the definitions of the columns of the table.A bit below, in the "items" aggregation,
we have the definition of the different cells.
00:02:59 And you see that for the first cell, the control "ObjectIdentifier" is being used for display.The
"ObjectIdentifier" has an additional property, which is called the "text".
00:03:13 I can simply add a data binding here and point this to the supplier name.And I will also go to
"Object.view.xml". In the object view, there's an "objectHeader".
00:03:40 And this one has an aggregation called "attributes", and I will add a single attribute for the
product name.You see that SAP Web IDE is helping me here with a code preview, with
potential candidates.
00:04:04 "ObjectStatus" is not the one I want, it's "ObjectAttribute".And the "ObjectAttribute" again has a
text property. Also for this one I will point to the supplier name.
00:04:24 Enough changes for now. Let's save this and run the application.I see that the supplier name is
displayed on the detail screen.
00:04:38 And also in the table it's displayed below the product ID.So far, so good.
00:04:48 Now that we have added, let's fix some of the screen texts.You can see here, this title of the
table looks a bit technical.
00:04:57 The same here, so we will fix some of these texts.To achieve this, we go to the "i18n" file.
00:05:08 Here you say the texts generated by the template are not good for human beings, so I'll fix
this.Let's say the title of the table is "Products".
00:05:21 I'll do this one more time down here for this text, which also includes the number of
products.This is the title of the object view, "Product".
00:05:43 Last but not least, let's change the title of this column to "Product".And on rerunning the
application, we see that this looks better now, so here we have some nice texts.
00:06:02 Actually there's a bunch more texts you could fix in here.For the sake of simplicity, we're
omitting these.
00:06:09 If you fancy it, feel free to go through all the lines and fix those texts.Okay, so much for that.
Now we can tackle the new columns.
00:06:24 And I'll copy some code for that...and I go to "Worklist.view.xml".
00:06:36 As I said before, here's an aggregation to the columns of the table.Here we see the two
existing columns,
00:06:45 and in between them I will add an additional column. This one is for the supplier.Now here's
the interesting piece.
00:07:00 You see two new properties. One is the "minScreenWidth", which is set to "Tablet".Basically,
this means: "Do not show this column on a phone; show it on a tablet, desktop, or anything
larger, but not on a phone."
00:07:17 Then we have this other property called "demandPopin", which is set to "true".And with this we
tell the table: "If you don't show the column, at least show it in a popin."
00:07:35 So that was the definition of the column.We need something to display the cell. I'll use a simple
"text" control and display the supplier name.
00:07:50 And last but not least, we need some text.So I'll add this additional text for our new column.
00:08:06 So far, so good. That should do the trick.I open the application, I press "Refresh",
00:08:15 and here we go, we see one additional column, titled "Supplier", in which the supplier is being
displayed.So far, so good. Let's continue with the supplier address...
00:08:41 I'll add a fourth column to the columns.Let's have a look at the responsive properties. Again,
"minScreenWidth" is set to "Tablet",
00:08:55 but this time the "demandPopin" is set to "false", so if we don't show this column, we don't
show it at all – not even as a popin.
00:09:12 Then we continue with defining the cell.This time I'll use a different control – the "Link" control.
00:09:23 The "Link" control has a text property that displays the link, and we are pointing it to this path:
"{ToSupplier/WebAddress}".
00:09:35 This information, the supplier information, is not actually part of the product business object, so
that's the product business object, and there's another object, the supplier object,
00:09:45 and there is an association between them.This association is expressed in the metadata
model with "ToSupplier".
00:09:55 Then on the other object, the supplier object, there's the property "WebAddress".So I use both
of these for the text, as well as the physical address that the link is pointing to, that's the "href".
00:10:10 And last but not least, I've set the target on the link, that's actually a browser feature, to open
the target of this link in a new window.
00:10:23 So far, so good. For now, let's bring in this missing screen text, that's the title of this column,
"Web Address",
00:10:38 and rerun the application.Here we go.
00:10:46 Only that wrong property is being displayed here. It's not the link.So I must have done
something wrong.
00:10:56 Ah, classic mistake – I haven't saved this file, which is indicated by this little asterisk up
here.So I'll save this file, I'll rerun the application.
00:11:09 And now, even though it's not really good, it's better.We see there are empty cells under "Web
Address". Nothing is being displayed yet.
00:11:20 Why does this happen? I've actually done everything right, but as I said before, this data is not
part of the product business object.
00:11:29 And the data binding is configured in such a way that it only loads the products.What we need
to do now is expand the first call for the products with the supplier objects.
00:11:44 This is achieved by adding additional properties to the data binding.So this is the "Table"
control, here is the data binding on the "items" aggregation,
00:12:00 and I'll add the parameters...I'll set the "expand" property to "ToSupplier".
00:12:20 Let's try again.Now we can see the links.
00:12:26 So with the very first call to the server to fetch the products, the supplier information will be
directly included.This is what we have just achieved.
00:12:38 Okay, so far, so good. We have built all the features we want to have into the application.Now,
let's test the responsiveness.
00:12:49 And actually there's a bunch of different approaches. Let's look at them step by step.First of
all, let's resize the browser window.
00:13:02 At a certain stage, when we are running out of space, we see that the columns disappear.And
only the first column is still kind of visible – it's being displayed with what we call the popin.
00:13:18 But the Web address has completely disappeared, because we think it's not so important and
we don't need to see it on the phone.
00:13:29 So this is actually a very comfortable way to test the responsive behavior of a table.But in the
real world you should test it differently
00:13:44 because there are other controls which not only depend on the screen size, but also on other
things, for example, whether or not there's touch support.
00:13:55 And to really test this properly, we will use the developer tools of Chrome.So I open the
developer tools by pressing the "F12" key.
00:14:08 Here you'll find the "Toggle device mode" button in the toolbar.When I press this button, you
see that the display on the left-hand side is adjusted.
00:14:21 Here we have a bunch of options and I can choose devices, I'll now choose "iPhone 6".
00:14:31 You now see that the application is displayed as it would be on an iPhone 6.Same result as
before: both columns become hidden.
00:14:47 You can enter the device mode by pressing the same button again.But before we do that, let's
see how it looks on a tablet, for example, we'll choose the iPad,
00:15:00 You now see running the application on the iPad still shows those two columns.Okay, with this
we've finished in Chrome.
00:15:11 I'll switch off the device mode by pressing the same button again, and I'm back with the
original application.
00:15:19 I'll also close the developer tools.Last but not least, there's a third approach that I want to show
you.
00:15:30 In SAP Web IDE you can open the "Run" menu, and here you can edit the "Run
Configurations".
00:15:43 We'll choose our "App" run configuration which we are using to run the application.For the
preview mode, there's an additional option, it's called "With Frame".
00:15:54 I'll choose this option and I'll save and run this configuration.Again the application is being
displayed, only this time you have additional controls at the top of the screen.
00:16:10 Here I can also influence the behavior.I'll now switch to a device with a smaller screen.
00:16:19 Again, as before, I can observe the behavior that the two columns become hidden on a phone-
sized device.
00:16:31 All right, so much for that.So this was the responsive table.
00:16:35 With this, we end the first unit for extending our application. Thank you.
Week3 Unit 3
00:00:10 Welcome to Week 3, Unit 3 of our openSAP course "Developing Web Apps with SAPUI5". My
name is Michael, and in this unit, we will make the table a bit smarter by adding quick filters.
00:00:23 The table that we extended with additional fields in the last unit can then be filtered easily.Let's
have a look at our app project again before we start.
00:00:33 If you have done the previous exercises, our "Manage Products" app should look like this. A
long list of products is shown on the main screen.
00:00:42 But how can you easily find products that are in a certain price range? Well, we could extend
the search so that it contains the price criteria,
00:00:51 but it would be a lot simpler to add predefined filters for the table.We want to filter our table so
let's go to the Explored app and check whether there's a filter example for that.
00:01:04 I'll open a new tab and go to the Demo Kit, and from there I'll jump to the Explored application
00:01:13 and I'll filter for "filter" to check what we have in store for that.So there are lots of different
controls, but we already know the icon tab bar from the previous units.
00:01:24 Let's check out the samples here.There's a nice filter example here.
00:01:30 It also contains a table.When you click on one of the icon tabs here on top – the sign with an
icon and the number – you can filter the table below.
00:01:41 This would be nice for our application, so let's go to the code panel here and copy the code for
the icon tab bar.
00:01:51 So I'll select everything for the icon tab bar, I'll press Ctrl + C to copy it in the clipboard, then I
can go back to my project, open the "Worklist.view.xml" and put it in here.
00:02:06 We put it inside the page, this time it's a semantic page, you might know the standard page
from the first week, and just put it inside here.
00:02:17 We will put the table from the previous unit inside the icon tab bar.I'll mark all the "Table"
code...
00:02:28 and put it in an aggregation named "content" here.Let's see how this looks.
00:02:39 Now you can see that the table's actually inside this "IconTabBar" control.If I press on one of
the keys, nothing's happening yet, we're about to change that.
00:02:48 If I click on it again, I can even close the icon tab bar and the table is completely hidden.This
would not happen if you put the table outside the icon tab bar,
00:02:58 so that's why I quickly refactored it.There's a lot of space around the table here.
00:03:04 We can quickly check the view code again.Let's see, there's probably something around the
table here.
00:03:15 So we have the "sapUiResponsiveMargin" class that we will just remove. And on the icon tab
bar, the "sapUiContentPadding" is also active, which I'll remove,
00:03:31 so that the layout is actually a bit nicer in this case.Now you see there's a lot less space, the
layout is fine,
00:03:39 but we should also adjust these icons and the text here to match our scenario.We said we
wanted to filter for "Price", and we can simply change the filter texts here in our view.
00:03:52 Instead of saying "Ok" here, I'll put "Cheap" in the first one, and I'll also put the key to "Cheap",
00:04:00 and the second one is actually "Moderate", and I'll change the key, too.The last one is
"Expensive".
00:04:17 Now we have updated the text here, too.Okay, using keys of the "IconTabFilter" control, we
can later define conditions on how to filter the table below.
00:04:30 For simplicity, we will skip adding the texts to the resource bundle, and just hard code them in
the view, but you should do so in the exercises to become more familiar with the translated
texts.
00:04:44 Then there's the "All" option here, containing the key products, which already matches our
scenario, but "count" is bound to some data binding thing from the example, so I've just put
"All" in here.
00:04:57 Then you can see that there's some large text here, which will be used to reset the filters in the
table.Good. It already looks nice, but the icons still don't really match,
00:05:11 so let's go back to the Demo Kit, and as Janina showed you before, we have this great tool
called Icon Explorer.
00:05:20 There's even a category called "Money".Let's see if we can find some nice icons for "Cheap",
"Moderate", and "Expensive" use case here.
00:05:32 For "Cheap", we could use this one, "waiver", for example, and for "Moderate" we can use
"loan",
00:05:46 and we can use "money-bills", this pile of money, for "Expensive".Let me just change the icons
here.
00:05:56 This one's coming from the icon font.So it was "loan", "waiver", and I think the last one was
"money-bills".
00:06:11 Let's check again.Okay, that looks much better.
00:06:18 The filters are still not really connected to the table, so nothing happens, but the UI is already
pretty nice here.
00:06:29 Let's select and see what happens.In the icon tab bar there's a "select" event that we can use.
00:06:39 Actually I'm going to format this one a little bit so it looks nicer.The "select" event can be bound
to a controller method again
00:06:46 and I'll put the method "onQuickFilter" in here, which we can then use to actually define the
filtering logic in the controller.
00:06:57 So this one will be called when the user clicks on the filters, and we can do the rest in the
controller coding in JavaScript.
00:07:05 I'll go to the "controller" folder and open "Worklist.controller.js".We can see that the base
objects for filters, namely the "Filter" and "FilterOperator" objects,
00:07:17 are already loaded in this controller because they are used in other places.After the "formatter"
definition, we will now add a new "helper" object.
00:07:27 I will call this "_mFilters" So this will be the helper object for storing our filter objects.
00:07:39 I'll give it the same keys which we used in "Worklist.view.xml".Let me quickly check this one
again.
00:07:45 For example, "Cheap", "Moderate", and "Expensive", put them as a name here.And for now
we'll just put an empty object here...
00:08:01 ...and "Expensive". The last one's without a comma.And be sure not to forget this comma here,
otherwise you'll get a syntax error in the controller.
00:08:12 The reason I've called this with an underscore is that JavaScript doesn't really have a private
scope, and users can access everything that you define in the controller.
00:08:23 By adding this underscore, I signal to the users that this one is actually private and that they
shouldn't access it.Okay, so we have our helper object, and now it's time to define a filter for
each tab.
00:08:38 Let's start with the "Cheap" one.We can now use the filter object and create a new filter here.
00:08:46 The first argument is actually the data binding path to the product.So the price of the table is
bound to the path "Price".
00:09:03 I'll take this one...Then the second one is a filter operator,
00:09:12 and we define "cheap" as a price less than 100.So this way I can define abstract filters in
SAPUI5 without having to touch the model,
00:09:26 and you can see later how this one is applied.Let's go back to our presentation for a second
because there are more options for filters.
00:09:37 Here we can see what we just did.We created a filter object, defined a path, an operator,
00:09:43 and then there's one or two values, depending on the operator.We've used the operator "LT"
(less than), which you can find here in the numeric section.
00:09:54 So there are different types of filters you can Some are for strings, like "StartsWith",
"Contains", "EndsWith".
00:10:03 Then there are numeric filters like "BT" (between), "GE" (greater or equals), "GT" (greater
than), "LT" (less than), so typical logical values.
00:10:11 There are also some that work with both string and numeric values, for example "EQ" (equals)
and "NE" (not equals).For more information, you can check the API documentation, which is
linked here and in the exercises.
00:10:26 So if a standard filter function is not enough – this is not really the case for our exercise, but
just for your information –
00:10:34 you can also specify a test function and then just define a JavaScript function that tests only
the value.
00:10:49 Then you can also combine multiple filters, either with "and" or with "or", and this is done by
passing in an array as the filters argument
00:10:59 and telling it how it should be logically concatenated.Okay, so behind the scenes, the filters will
be translated to corresponding operations on the model, as I've said before,
00:11:14 and as you saw in last week's unit.Good. Let's go back to the code.
00:11:21 I've defined the first filter.We've also seen on the slide that there's a "between" filter that we
want to use for our second condition,
00:11:29 this one then gets two values.For my "Moderate" filter, I'll also use the "Price" path,
00:11:38 but now I'll use the operator "BT", then I'll say between 100 and 1000 is a moderate price,
00:11:50 and "expensive" for me – let me just copy the first one – is a price greater than 1000.So these
are my three filter objects. Now we just need to apply those on the table.
00:12:08 If I call my application in this state, nothing will happen because it's just defined on the
controller.So we have this "select" event on the icon tab bar.
00:12:23 I now just need to define this function on the controller that helps me with setting the filters on
the table.And in the controller, we have different lifecycle methods here, and also an event
section.
00:12:36 I'll put it at the end of the event section, so right here after "onRefresh", a new function that will
be called if the filter is pressed.
00:12:51 Now there's a standard parameter to this function in UI5.It's basically for all the events, and
we'll pass in the parameters for the event.
00:13:01 Let's go back to Explored and check the icon tab bar again, what the event parameter is for
this event.
00:13:09 We are going to use the "select" event.I'm interested in the key that I want to read from the
event,
00:13:17 so I'm going to say my key is from the event parameter, then I can call "getParameter" and
pass in the
00:13:31 So this is the first thing that I need in this method...Just checking again if the name's right.
00:13:39 Now this is the "selectedKey" that I need.Oh wait, this one is actually deprecated, so
sometimes we rename the properties,
00:13:48 "key" was right, "selectedKey" is just the deprecated version of it.You should always use the
latest one that is not a marker of this deprecation hint.
00:13:59 Okay, we have the key now.What else do we need?
00:14:03 We need the filter object that I have stored in my helper object.I can access it with
"this._mFilters",
00:14:15 and I can use this key that I've just fetched to get the corresponding filter for my helper
object.One more thing we need is the table instance because the binding of the table needs to
be changed.
00:14:31 We can also get this one with another pointer that is defined in the "init" method up here.Here
you can see "this._oTable" is set to the table instance in the "init" method,
00:14:48 so it's a helper method that we can use.So I say that my binding – I'll fetch from the table – is
"getBinding",
00:15:02 and I just need to specify the name of the aggregation.Now I can get the binding for the
aggregation items from the table,
00:15:11 and this is the place where I put the filters on, so filters are applied on the binding level,
00:15:16 with data binding and not on the table itself because the UI will update automatically.Good.
00:15:26 One more thing to do here.So we can now say "oBinding.filter",
00:15:35 and we pass in the filter object here.Then everything is also without errors, and we can see if it
works.
00:15:47 Okay, cross your fingers..."Cheap"..."Moderate".
00:15:55 Okay, nothing's happening yet. Let's check the console again, and it says this "getBinging" is
not a function, which is of course correct.
00:16:04 I have a typo here, so this is "getBinding".Let's try again...
00:16:13 and see if it's working now.Now you can see if I press "Moderate" filter it's actually narrowed
down to 45 products.
00:16:22 If I press the "Expensive" filter, it's getting even less with 20 products.Good! So we have
successfully filtered the table.
00:16:33 Now it's time for something different.We want to take a look at the color scheme we have just
set in this icon tab bar.
00:16:40 We've actually just copied it from the "Explored" sample.You can see that the "Cheap" filter is
green, "Moderate" is orange, and "Expensive" is red.
00:16:51 Why is that? It's because the icon color is set to "Positive", "Critical", and "Negative",
00:17:05 which is like a semantic value for colors.This is how colors are most often defined in SAPUI5,
00:17:13 and will do the job for us.So instead of specifying the colors directly, I use the semantic values
and give them a meaning.
00:17:26 Let's take a look at how the color scheme in SAPUI5 is defined in general.You can see here
that colors are a really important concept when defining an application.
00:17:38 For once, it's a layout thing, but it's also about meaning and semantics.If you've wondered why
most apps written with SAPUI5 have this blueish color scheme,
00:17:51 then it's by intent, because this is the Fiori design language that we have specified for our
controls.This is default theme called "blue crystal".
00:18:03 The color balance shows that there is only one main bright blue color that is used to highlight
important elements on the screen, and a lot of soft-blue and grayish colors that are used for
the rest of the UI,
00:18:20 and only a very minimal representation of bright colors.You can see the effect in the
application because the filters actually stand out quite well in front of the rest of the table.
00:18:33 The table is defined in these subtle colors and the header's quite bright.If we had used a lot of
colors in our application, this would not really have stood out.
00:18:46 In general, you should only use colors sparingly to keep to this concept and use predefined
accent colors for anything else that you need.
00:18:55 These are defined in the framework, too, and you can find some theming examples in the
Explored application, where you can find more information.
00:19:16 In these samples here, you can see that we have different colors defined as "accent" and
semantic colors which you can use to color your app.
00:19:28 This way, a customer or user can later use a tool called Theme Designer to brand their
application to their needs and redefine the colors.
00:19:39 Good.There's also more information on this in the Demo Kit and in the Developer Guide.
00:19:47 For now, I just wanted to show you how this looks in our application.Okay. One more thing to
add about our icon tab bar here at the top
00:19:59 is that I would actually see how many items match these criteria before I click on the
items.Now I have to click on the "Moderate" filter to see that there are 45 matching items,
00:20:11 but I don't see it in advance.We could do this by querying the service
00:20:18 and fetching the number of products that match right before we click on the item, and we bind
discount values to the "IconTabFilter" controls,
00:20:29 then we can see it in advance.So let's go back to our code and add some more details here.
00:20:37 This is where we use the "count" properties which are still bound to this value from the
Explored sample, I will bind it to a model called "worklistView",
00:20:48 which you'll find out about in a minute, then to path called "Cheap".
00:20:55 I'll just copy this for the other two values..."Moderate" and "Expensive.
00:21:06 So now we have defined the counts, but of course, if I now call the app, it's still empty,
00:21:10 I haven't defined them yet in the controller.Oh, wait a second.
00:21:17 You should also close the binding syntax here, otherwise it won't work.You can also see that
it's good to try quite often, then you can find errors quicker.
00:21:31 Okay, the numbers are not set yet. I will do this in the controller code again.This is also where
the "worklistView" model is defined.
00:21:43 In "Worklist.controller.js", and in the "init" method, I can see this view model, which is then set
on the controller with the name "worklistView".
00:21:56 I'll add three new properties here..."Cheap", "Moderate", and "Expensive".
00:22:07 I'll initialize them all with "0" because this is what will be displayed until the data from the back
end is loaded.Later we'll update this number, when the data is fetched,
00:22:20 and then update it to the real value.There's one handy method here on the controller called
"onUpdateFinished".
00:22:28 You can read here in the comments: "Triggered by the table's 'updateFinished' event: after
new data is available".
00:22:35 This is exactly what we need.We'll just hook in here and do something.
00:22:42 The first thing I want to do is fetch my view model instance, just as a shortcut.I can do so by
calling "this.getModel("worklistView")",
00:22:55 then I can later update the texts here.It's not used that. That's fine.
00:23:07 And here is the branch of the "if" statement that is called when the data is there.I'll just put
something called "jQuery.each" here.
00:23:19 I'll iterate on my internal filter object and execute a callback function that receives the key and
the filter object for each of these filters.
00:23:42 So basically "jQuery.each" executes on each of these entries of the array function that I
specified here.For each filter, I want to do something on the model.
00:23:58 And I do... just wait a second...yeah, I need a reference to the model, too.
00:24:08 For this one it's the default model, so I can just pass in no arguments.Then I can say
"oModel.read", which is like a manual read operation on the model,
00:24:20 and then pass in the path to the data binding, which is "ProductSet" in our case.Then there's a
special "oData" parameter that you might remember still from the data binding week, called
"count".
00:24:34 And this one will return the number of items to By default, it would just return all the items, but
I'm interested in the ones matching my filter,
00:24:45 so I can also pass in filters, and pass in the filter for each of these.
00:24:55 Okay, let's just make it logically correct.Good, so the read operation is called with the path,
00:25:06 and now gets the filter for each of these filter objects.We can also specify a success handler
function,
00:25:18 which will then receive the data from the backend service.So it's an object with certain
properties for "count".
00:25:29 It's very simple, it's just the number of items.Finally, I can set this on the view model by calling
"oViewModel.setProperty",
00:25:42 and give the path.The path is... I think it still needs to be constructed... let's just check...
00:26:04 So I'll pass in the data from "count".The path is very simple.
00:26:16 It's just "/" for the absolute path, and then the key afterwards.Let's just quickly try it out.
00:26:25 It was quite some logic, so we'll be lucky if it works in the first place, but we'll see.Okay. Let's
quickly recap this.
00:26:36 "jQuery.each" calls the "callback" function on each of the filters, and here we have defined the
"Cheap", "Moderate", and "Expensive" filters in this helper object,
00:26:46 so the function is called three times.It will set off "count" against the model,
00:26:53 pass in the filter for each of these functions, and then execute the success function, which will
then update the view model,
00:27:01 and hopefully it will also update the view because the view model is directly bound to the
table.Okay. Technically, these requests are sent in a batch request,
00:27:12 because for performance reasons it's actually better to put them all in one request and let them
run at once.Otherwise it would trigger three separate requests to the back end.
00:27:24 But from a coding perspective, it's the same, so I'll call "oModel.read" three times.
00:27:30 Okay, let's call the app again and see what happens.There we go. Initially you saw there was a
"0".
00:27:42 I can do it again...First "0", then after the table was loaded, the counts were updated
automatically.
00:27:53 We've added quite a lot of code to our project, but it's certainly made the table more usable, as
we can now filter the products by price.
00:28:01 So it's really helpful.I can also close the table if I want, if I need more space,
00:28:07 and I can filter for the products quite easily.Okay. That was just one of the filter patterns that
we have in SAPUI5.
00:28:17 In our app, we wanted to keep things quite simple.But if you want to allow more complex user
selections and criteria for filters,
00:28:26 you can check these patterns in the Explored app.There are many options and you can
choose the control that best matches your development scenario.
00:28:35 For example, we have this "SmartFilterBar" in the "sap.ui.comp" namespace, which can be
used to define very complex conditions.
00:28:46 There's also "FacetFilter", which is like a dropdown menu with filters.And this
"ViewSettingsDialog", which is frequently used to filter tables as well.
00:28:56 So just pick the one that you find useful for your application project, and just try it out.That's all
for this unit.
00:29:06 In this unit, you have learned how to create quick filters for your table, and you have seen how
to create logical filters.
00:29:13 And also we have talked a bit about semantic colors in SAPUI5.In addition, you have seen
how to manually trigger read operations on the model
00:29:22 and how to use the local view model in a controller.If you have any questions, post them in the
discussion forums and we will get to you.
00:29:33 In the next unit, Andreas will show you how to adapt your app to the user's device. Thank you.
Week 3 Unit 4
00:00:10 Hello and welcome to Unit 4 of Week 3, "Adapting to the User's Device".My name is Andreas,
I'm a Development Architect in the UI5 area.
00:00:19 As you know, UI5 can be used in rather different devices, from huge desktop screens to small
smartphones. Some even run it on smart watches.
00:00:28 These devices have very different screen sizes and user interaction paradigms, for example
touch support.A really great user interface adapts to the device it is running on.
00:00:39 In Unit 2 of this week, we already learned how the table can be made responsive to screen
sizes, but there are many more options, which we will explore in this unit.
00:00:52 In UI5 there are many controls that automatically adapt to the screen size.For example,
"SplitApp", which is used here to display two different pages side by side on desktops,
00:01:03 will show these pages one by one on a phone, so the user sees one page and can navigate to
the other.Or another example, "Pull Down to Refresh", marked in orange here.
00:01:14 In touch devices, the user pulls down the page to refresh the data.In desktops browsers,
there's no reason for pulling something, there's a button to refresh the list.
00:01:28 This happens automatically, so the application doesn't need to take care of this.Another
example is the layout of the form here, or the object header.
00:01:38 So while all of this comes for free, it's still good to know that UI5 has this capability.But you can
make the app even more responsive. So let's have a look at the options we have for doing so.
00:01:49 Let's do it in the application we have developed so far.Currently, the app looks like this: We
have a list on a front page and a quite empty product page.
00:02:03 So let's add some content here to explore the responsiveness options for SAPUI5.I've
prepared some content here...
00:02:17 which I will now paste with the Object.view.xml file, below the object header, to have more
content on this page.The content I have now pasted consists of three panels.
00:02:30 The first one contains a form with information about the product, the second panel contains a
list with information about the supplier
00:02:42 and the third panel contains a map showing the location of the supplier.Because we have used
a new XML namespace for the form, we need to also add it in the root tag of this XML
document...
00:03:09 When we have done so, we can try to reload the application and check what happens.All right.
You can already see some content has been added.
00:03:17 There's the "Product" panel, and there are the "Supplier" and "Map" panels, neither of which
has the complete data yet.In the "Supplier" panel, you see we have followed an association
inside the data model.
00:03:33 In this case, we need to add this association to the data by using an "expand" parameter.This
happens in "Object.controller.js", the method is executed, and the app navigates to the second
page.
00:04:02 So this is the "bindView" method, which is called to bind the data on the "detail" page from the
"product" page, and we add the expand parameter "ToSupplier".
00:04:15 So let's reload the application, and you see the supplier information is now there.
00:04:22 Very good. But the map is still missing.So, let's check what the map does.
00:04:30 The map is actually just an image that is loaded from a certain location which is given by this
formatter here, by the "formatMapUrl" method,
00:04:38 which gets some information about the supplier location from the data model.So we need to
implement this formatter. Let's open "formatter.js"...
00:04:57 and add this code to implement the formatter we need here.The "formatMapUrl" method gets
the information about the supplier location and returns the URL to Google Maps API,
00:05:10 which returns a plain static image – so not a functional map, just an image – showing the
location we have given.Okay, so we save it and reload the application again.
00:05:25 We see the map correctly shows the location of SAP – in Walldorf. Very good.So when we
resize this application,
00:05:39 we see that not much changes, the form layout changes a bit, and the paddings to the left and
right of the panels get smaller and vanish when the screen or window size changes.
00:05:52 This is due to the SAPUI responsive margin classes that I have already added to the
panels.You have already heard about these classes in a previous unit, but there are more than
these.
00:06:05 So if you go to the UI5 Demo Kit and search for "Options for Further Adaptation", then you see
differences as classes that can be used to add responsiveness to your app.
00:06:19 For example, the responsive margin classes that we have just seen.Also others that can be
used to hide or show controls depending on the device,
00:06:28 for example "VisibleOnlyOnDesktop" or "HideOnDesktop".Let's use "sapUiHideOnPhone".
This class of course makes a control invisible on a phone.
00:06:38 Let's pick the map and make this map invisible, and we are running the application on a
phone.
00:06:45 So just add the "sapUiHideOnPhone" class, save the view, and reload the application again.
00:06:58 We see the map is still there, and when I resize the screen, eventually it vanishes.There are
other options to adapt your application to the device.
00:07:14 One important thing for doing so is the Device API, so that's the "sap.ui.Device" class.This
class contains a lot of information about the device the application is running on.
00:07:26 For example, the browser name and version, the operating system and version, the kind of
device it is – a phone, tablet, desktop, or even a combinable device that has mouse and touch
interaction,
00:07:37 screen sizes, support for certain features like touch support, WebSockets, retina display, and
so on.So lots of information inside this object.
00:07:47 You could, for example, use this object just to decide which view or content you want to
display, but let's do something a bit trickier and more interesting.
00:07:58 Let's create a device model, because this device class is more or less just a data structure.You
can put it into a JSONModel,
00:08:07 and then use this JSONModel containing the device information to use data binding to
declaratively influence the UI depending on the device that UI5 is running on.
00:08:20 This is already implemented in the application template that has been used to create our
application.So let's go to the code and check where this happens...
00:08:34 This is the "models.js" file.Where this is done it has a method called "createDeviceModel"
which instantiates a JSONModel,
00:08:45 and gets the device API, the data of this JSONModel.Then we have to set the binding mode of
this JSONModel to "OneWay",
00:08:55 because otherwise there would be a danger of the application overwriting data in the device
API and we don't want to modify it, like the device we're running on.
00:09:07 This method is called in the "Component.js" file... that's here...It sets this model with the name
"device" on "this", so on the component,
00:09:24 so inside the entire application, this device model will be available with a device name.Okay,
let's use this model now to make something responsive with data binding.
00:09:39 Let's go to the object view again, and we now want to have these panels, which were all
displayed one on top of the other,
00:09:48 to display them as expandable panels.Currently, they are always visible, but I want these
panels to be expandable when we're running on a phone.
00:10:00 So, bind "expandable"...I want to use data binding to bind to a model "device",
00:10:15 and we bind to the path "system/phone".So this flag contains the information on whether the
current device is a phone,
00:10:25 that's not only the screen size, but really whether it has touch support and is small in size.We
also want to have this panel expanded by default...
00:10:40 and do the same to the second panel, but we don't want to have this one expanded by default,
so "expanded" is "false", but still it should be expandable on a phone.
00:10:51 The third panel is hidden on the phone anyway, so we don't care about it.Let's try and reload
this application...
00:11:02 Ah, nothing's happened so far and that's, as I said, because it only reacts on real phone
devices.Or we can apply a trick on simulated phones, so if you use the Chrome device
emulator...
00:11:18 and you use phone simulation, then really it behaves like a phone, and UI5 thinks it's a
phone.Let's reload this page...
00:11:28 and you see we now have these arrows here, which can be used to expand or collapse a
panel.You see the second panel is collapsed, the first one was expanded by default, and now
it's expandable.
00:11:47 So you see, you have used data binding to make the application responsive without even
writing any code. The final topic I want to mention in this unit is "Content Densities".
00:12:01 The sap.m library has lots of controls that are pretty large, so they can be used easily with
touch interaction.You can see it on the left here.
00:12:11 But in desktop browsers, where the user has a mouse, they don't really need to be that large,
so the user can easily click buttons when they are a bit smaller than needed on touch devices.
00:12:21 Therefore, many of the controls have a "compact" and a "cozy" mode, different sizing modes,
and you can control which mode should be used by adding a certain CSS class –
sapUiSizeCompact or sapUiSizeCozy.
00:12:35 Again, this implementation is already available, inside the application template we have used
to generate our application.So we can go to the code again...
00:12:51 Go to "Component.js"...This will give us the "getContentDensityClass" method.
00:13:00 This method is used to return the CSS class we want to apply.So first it checks on the
document body whether there is already a class – cozy or compact –
00:13:10 which could be the case when the application isn't running inside the SAP Fiori launchpad,
which already has some content density handling.
00:13:17 But if there's no such class, then we'll make the decision.If we have no touch support, then
there's no need to have the big controls, then we set the compact class.
00:13:29 Otherwise, if you have touch support, you'll need the "cozy" mode.This content density class-
getter is then used in "App.controller.js",
00:13:44 you can see it here in the last line, to add the reciting style class to the root view of the
application.
00:13:53 It's done in this "reuse" method because popups are not below the root view, but in the HTML
document, they are hanging next to the root of the document, they are directly at the root of
the document.
00:14:06 Therefore, the same CSS class also needs to be applied to popups when popups are
opened.So, you see the content density implementation is already done, you don't need to do
anything about it in this app,
00:14:19 but it's still good to know if you create other apps or if you want to change the behavior here.By
the way, also in the Explored application, you can go to Settings,
00:14:29 and change between "Compact Content Density" and "Cozy Content Density".Let's do the
compact mode here and you'll see in the background that everything gets a bit smaller.
00:14:39 You can check the appearance of all the controls here, in "Compact" and in "Cozy" mode.So to
sum up this session, there are several means of adapting UI5 applications to the device it's
running on.
00:14:56 Many controls adapt automatically, so you don't need to do anything, but other controls can be
configured to adapt.
00:15:05 There are predefined responsiveness CSS classes that you can use to apply to certain
elements and make them hide, or to make margins grow or shrink.
00:15:17 There's the content densities we have just seen.There's also the device API, where you can
get any information about the device and make your own decision
00:15:25 to show something or hide something, or show something else, or even use it for data binding
as a device model.
00:15:33 By the way, adaptation is not only a visual thing.You should also think about GPS sensors,
about cameras of devices,
00:15:42 so there are other things you can make use of if they are available.All right, so that's it for this
unit.
00:15:51 The application has grown quite a bit in this unit, so in the next one, my colleague Christiane
will show you how you can even better structure large applications,
00:15:59 and how fragments help you to reuse parts of the user interface.Thanks for your attention.
Week 3 Unit 5
00:00:10 Hello, my name is Christiane.Welcome to Week 3, Unit 5 – Fragments and Code Reuse – of
our openSAP course “Developing Web Apps with SAPUI5”.
00:00:21 In this unit, you will learn more about how to create reusable code, and structure your
application resources conveniently.
00:00:30 We will cover view nesting, fragments, typical folder structures in your app and other reuse
objects which can be extended, for instance a base controller other controllers inherit from.
00:00:43 Let's first inspect the current state of the application.Currently, we have two views in our
application.
00:00:51 When we have a look at the object view code, so we need to go to the Web IDE,
00:00:57 open the view, and inspect what is already there, we can see that it has grown to quite a
number of code lines.
00:01:12 What's more, the code in there is not very modular.And when we want to reuse parts of it, we
would have to copy them over. Or would we?
00:01:20 No, of course not, because UI5 allows us to solve such reuse issues in clever ways, for
instance with fragments.
00:01:31 If you find that you are reusing a certain control with some specific settings or a set of controls
in several places in your application,
00:01:39 you can use an element of SAPUI5 designed for this very purpose – a fragment.A fragment
can contain one or multiple controls, and it does not have its own controller like a view usually
does.
00:01:54 However, it can get access to the parent view controller, depending on how it is instantiated.It
is a very lightweight element in SAPUI5, and will simply have its controls rendered wherever
you include it.
00:02:09 At runtime of your application, a fragment's content will be indistinguishable from other parts of
your view, so there will be no encapsulating DOM element surrounding it.
00:02:21 It can be included in an XML view with just one line of code, just as a simple control.Let's see
what this code would look like.
00:02:33 We will first create our fragment file in our view folder.We will call the fragment
"SupplierInfo.fragment.xml".
00:02:39 So I'm creating a new file here.And just type in the name.
00:02:53 Next we will create the skeleton for our fragment.We need to have a surrounding tag which
opens the fragment definition.
00:03:09 And, just like in view, we also need to specify the corresponding namespaces.Note that I have
typed "core:FragmentDefinition" in here,
00:03:17 so I also need to specify the namespace correspondingly.As the default namespace, I will add
our SAP mobile library again, so "sap.m" will become the default.
00:03:33 I'll also add the core namespace here.Okay, so that's all it takes for the fragment definition
itself.
00:03:50 Now we can move code – we assume we want to reuse the code part – from the object view
over to the fragment.I'll go to "Object.view.xml" here.
00:04:02 And I'll simply cut out the info panels that we have for the supplier.This applies to the panel,
with the supplier title and the list in here.
00:04:17 It also applies to the part where I can see the supplier address.I will simply cut them out here,
save my object view,
00:04:30 and move the content over to "SupplierInfo.fragment.xml" and paste it in here.Now our
fragment is ready to be used.
00:04:42 We will now embed it in our object view, so I need to go back to "Object.view.xml" again,
00:04:48 and I actually want my content to appear at the same place as it appeared before I moved
it.The only line of code I need to add here in order to get access to the fragment is the
fragment inclusion here.
00:05:17 What I also have to specify is the fragment name.The fragment name is similar to the view
name,
00:05:25 kind of like the path to the fragment that you want to include here, so "FragmentName" is the
attribute I need to specify,
00:05:32 and because we are in our "opensap.manageproducts" namespace, I need to prefix this here,
and then I can just say, okay, it's in my view folder and I called it "SupplierInfo".
00:05:50 And now we also need to specify what type the fragment is, so I need to specify the type
attribute here again, and it is of type "XML".
00:05:59 Now I can close the fragment, and that is actually all it takes.Just briefly checking the
namespaces again. Do I have the core namespace here?
00:06:08 No, I don't. So I need to add this here.I'll simply copy one line over.
00:06:16 I'll delete "mvc" here and replace it with "core".Okay.
00:06:23 Now I can actually run the application, and at the moment it should simply look like it looked
before.
00:06:33 So when I reload it now here...still loading...
00:06:45 and I'll go to my object view now, you can see that the supplier information is still displayed
down here.So from the perspective of the front-end side, the client side, nothing has changed
currently in terms of runtime,
00:06:59 at least not as far as the user can see.Now, even when I look at the document object model
here – I need to open the developer tools here in Chrome –
00:07:13 I can see that there's actually, as promised, no trace of the fragment within my view.So when I
drill down here a bit, and go to my content area...
00:07:34 I need to dig a bit deeper...you can see that there are different sections in here.
00:07:41 And within this content section, I can see that there is simply my panel included.You can see
here, for instance, a panel header.
00:07:55 I can tell from the ID here – this is a generated ID – that this is the panel I'm looking at.And you
can see that there's no surrounding div that suggests that any other view or anything else is
involved.
00:08:07 So from this perspective, the fragment has not left any trace.I can close this again.
00:08:14 Fragments, however, are not the only container element you can use within a view.You can
also nest views into one another.
00:08:22 This pattern is very useful if you have parts of your UI which you want to reuse in different
places on your application.You also need to have a particular functionality available with these
parts, which you would include in a controller.
00:08:36 Nested views can have their own controllers, just as usual views.In terms of integrating a view
into another view, this is no different from embedding any other control.
00:08:51 In an XML view, you can again simply use a single line of code to include a different view,
which will then be rendered in this place.
00:09:00 On this slide, you can see that there is a nested view embedded into the surrounding view,
and you can see that it is simply displayed below the controls that are there.
00:09:12 On this slide, you can see again that it's one single line of code, which is printed in bold here in
the part below, where you can see how to integrate a view into another view.
00:09:25 Note that in the DOM of such an embedded view, there will be a development encapsulating
the view content.This makes it very easy to see whether some controls are coming from a
nested view by just looking at the DOM of the page.
00:09:40 Let's see this in action to understand what it means.Going back to my code...
00:09:46 We are now creating a view which will contain some of our product details, and we will call this
view "ProductDetails.view.xml".
00:09:54 So I'm creating a new file here again...We will first create the view skeleton again.
00:10:08 So I'll start with a view declaration, adding a few namespaces here...
00:10:18 The default namespace is "sap.m" again.And then I also have to specify the "mvc" namespace
because I'm already using it for the view.
00:10:39 Then I'll need to close this again, and here we have our view skeleton.Next, we'll again move
some content from our object view to our new view.
00:10:48 So I can already save this here... and go back here.What I will now do is simply take the panel
that is left containing some of the product details and move this into our new view.
00:11:04 So I'll just cut this out again here...and go to our new view that we have just created,
"ProductDetails.view.xml", and paste the code in here.
00:11:15 Now what is missing here – you know, when you copy code over, you need to be aware that
namespaces could be missing – what is missing here is the namespace for the form.
00:11:26 So I need to add this here...and it is pointing to "sap.ui.layout.form"
00:11:39 Now we can include the new view into our object view by just inserting a single line again.So,
just cleaning up the code a bit...
00:11:51 We need to actually specify this with the "mvc" namespace again because the view is found
there.And now we need to specify what type of view we want to include,
00:12:03 and in our case it is an XML view.Then there's one more attribute that we need to specify,
that's the view name.
00:12:12 Again, we have our namespace for our application here:
"opensap.manageproducts.view.ProductDetails".
00:12:28 Now I can close this again.When we now rerun our application...
00:12:39 It's still loading...You can see that the information is still there, and when I now open the
developer tools again,
00:12:49 and I pick the element where the product details are displayed, you can see that this is actually
an embedded view by looking at what the surrounding div here is.
00:13:03 You can see that there is now a div containing our panel, and this div has an ID which is again
generated by UI5 because we have not specified an ID.
00:13:13 This ID already contains the word "view".It's the "__xmlview0" that appears here which tells
you there's a different view involved.
00:13:25 As mentioned, a nested view can have its own controller, and hence come with methods
completely different from the surrounding view.What else can you do to avoid redundant code?
00:13:36 Well, you can extend your own code again.When we look at the controllers within our
application,
00:13:42 we can see that they are actually extending a class different from the standard SAPUI5
controller.So let me just open "Object.controller.js".
00:13:54 Here you can see that in our defined syntax that we were using to describe the controller, we
were actually – as a dependency – loading a controller that comes from our own application,
00:14:06 which is called "base controller".This is also the base controller that is extended down here.
00:14:14 So when you find that there's code in your controllers which has become redundant, and you
realize that you've started copying code from one controller to the next time and time again,
00:14:22 it makes sense to define your own basic controller class and implement this code right
there.The other controllers in your application can then extend this basic controller, and inherit
all the functionality from there.
00:14:35 And this is exactly what has happened here.So when we have a look at the base controller,
00:14:41 you can see that there is some convenience functionality that is already implemented here, like
the getRouter or the getModel function,
00:14:49 which makes it shorter to type.The same applies to "setModel" or "getResourceBundle".
00:14:56 A functionality like this which is convenient to use in every controller in your application can
then be implemented here and inherited.
00:15:05 And you can also create additional classes containing functionality like error handling, and
then declare this as dependency, for instance, in your component.
00:15:15 You can see that this is also what has happened here in this application.Below the controller
directory, you have another file that is just called "ErrorHandler.js".
00:15:25 When we open it, we can see that this is actually inheriting from the "base/Object" class in UI5,
and that it implements a lot of methods that are related to error handling throughout the
complete application.
00:15:43 The only thing that you then need to do is, as mentioned, to declare this as dependency in
your component, as you can see here, and then it can be used inside.
00:15:53 This makes it possible to keep your code in a well-ordered structure, and makes it easier to
read and maintain.One last method of structuring code in your application is that you do not
have to strictly stick to the folder structure
00:16:05 that we see here in our sample application.So you can see what is typically there is a controller
folder, a view folder,
00:16:14 a folder for test files, for the model, for resource bundles that contain our translatable text.And
maybe for a local service if you need to have some mock data in case your server is currently
not answering.
00:16:29 When you have a high number of different views, it can for instance be helpful for related
views and fragments to be put into subfolders.The same goes for controllers. Usually, you
would keep both these structures in analogy.
00:16:41 So when you create a folder for your products, and you have several views in there, you would
usually also create the same controller folder
00:16:50 in this base controller folder that you have here.For the fragment and the view we have
created during this lesson, this means we could, for example,
00:16:59 also have created a new subfolder under our view directory, and for instance name it
"ProductDetails".That's it for this unit.
00:17:08 You have learned about some of the major features and patterns allowing you to structure your
application in a well-ordered manner.
00:17:15 You have seen how you can create code in a way that it is optimally reusable within your app,
with the least redundancies in your code.
00:17:23 There is one more aspect we have not inspected yet, and which will also help you create your
applications: dialogs, and in particular dialogs in fragments.
00:17:33 This will be the topic of the next unit in this week.I look forward to seeing you in the discussion
forums.
00:17:39 Thank you.
Week 3 Unit 6
00:04:45 and I don't find the namespace for the layout library here, so I will just add it.I'll type "xmlns" for
the namespace, then I'll just use "l" for layout,
00:04:58 and put the layout library into this namespace.So now I can scroll down again, and I can use
the grid inside my responsive popover here.
00:05:15 Of course I need to put an "l" before "Grid", otherwise it's not going to be found.Okay, so I
have my grid.
00:05:21 For the sake of simplicity, within the grid let's just put four text controls displaying the label
texts, as well as the property values and the units of measure.
00:05:34 In real application, of course, these texts will also not be hard coded, but will come from the
resource model.Let's create the text fields here.
00:05:47 I will add these to the content aggregation of the grid...Let's create the four text fields for the
dimensions that we want to see here now.
00:06:01 They need to into the content aggregation of the grid.So I need to type that in here, opening
the content aggregation,
00:06:10 and now within here I can define the text fields.So I'll create the first text field now,
00:06:17 and as a text property, I will pass the corresponding label, for one thing.Let's use the width
first.
00:06:27 Then I will combine this with the binding to the corresponding property on the
service.However, we can reuse the formatter from the previous units in order to display the
dimensions a bit nicer.
00:06:39 I'm not just passing the path, I will combine this here, I need to type "path" in here and it's
pointing to the width property from the service,
00:06:49 and we will also pass a formatter in here.This formatter happens to be present at the formatter
object at our controller,
00:06:57 so I can start with a dot, meaning this is pointing to our own controller, and then I need to start
with "formatter", and the formatter was called "numberUnit".
00:07:10 So this is the binding part one, and then it let us also use the unit which we get from the
service, which is actually the service property "DimUnit" that we also need to bind here.
00:07:21 Now I can close this text field again, and I'll just copy this over to create the other three...and
fill them with the different dimensions that we also want to display.
00:07:42 Let us, for instance, use "Depth" as the second dimension, and maybe "Height" as the third.
00:07:52 Note that I always have to change the label text as well as the path here.And lastly, we want to
see the weight.
00:08:00 This weight, however, is not called "Weight" at the service, it's called "WeightMeasure", and
the unit is not called "DimUnit", it's called "WeightUnit".
00:08:14 As mentioned, we can use the formatter from the previous units to format our dimensions so
that they only display two digits.
00:08:23 From the service, there would be four instead.Now we still need to adapt the worklist view a bit
in order to call our popover from somewhere.
00:08:33 We will therefore set the "titleActive" property of the object identifier to "true", and define a
press handler we will call "onShowDetailPopover".
00:08:43 Let's see where the object identifier is.Okay, it's here.
00:08:47 We want to make the product ID clickable, so "titleActive" needs to be "true" here.The
corresponding event will be the "titlePress" event,
00:09:04 and this "titlePress" event is called "onShowDetailPopover" Now we have the link, what is
missing is the event handler in our controller.
00:09:25 We will add new methods in "Worklist.controller.js", just above the section where the internal
methods start.I have saved my worklist view and I'm now going to the worklist controller,
00:09:36 and I have already scrolled down to the point where the internal methods section starts, and
we will add our new methods below the last of the event handlers that have already been
defined in the previous units.
00:09:49 I will create a new event handler here, and as mentioned I will call it
"onShowDetailPopover".As "function" is an event handler, it gets the event object passed in
here automatically,
00:10:04 and we also need that in our event handler this time.I need to add a comma here.
00:10:11 So what I'm now going to do within this method is firstly get the popover by its ID.Now, in order
to do that, I can just say I'm creating a variable here,
00:10:22 "var oPopover", and I need to say "this.byId".Now the question is what was the ID of my
popover again, does it have one?
00:10:33 I need to briefly go back to my worklist view in order to see that...scroll down to my popover.
00:10:40 Yes, it has the ID "dimensionsPopover" here, so I will just copy this...and insert it into the
controller right here.
00:10:50 So now I have the "dimensionsPopover" instance that I need.Next I need to bind the popover
to the path of the element that has just been clicked on,
00:11:04 so the corresponding product path.And in order to do that – you remember we have the
function "bind element" available in UI5 –
00:11:14 I now say "oPopover.bindElement.Within this function, I now need to get to the path of the
source product that somebody has clicked on.
00:11:28 I can again say I get the "Event" object which I get passed into my event handler, and I can
say I want to retrieve the source of this event, so I can say "getSource", a method that you
should already know.
00:11:43 Then I can ask the source for its own binding context, so I can just concatenate this here and
say "getBindingContext".
00:11:54 However, for the bind element, you know that I actually need a path, so now that I have gotten
this binding context and it has returned to me,
00:12:01 I can also concatenate the "getPath" method here.Now I have all that I need for the binding.
00:12:10 To open the popover, I also need to tell the responsive popover where exactly to open
because it will position itself relative to the opening element.
00:12:22 I need to determine who the opener was.I can retrieve this by saying I want to have this
opener,
00:12:34 and this opener happens to be a parameter at the event object that gets passed into my
method because the responsive popover specifies that.
00:12:42 So I can say I want to have this particular opener, and I can get this by going to the "Event"
object again and asking for the corresponding parameter,
00:12:53 so I can say "getParameter", then I need to say I want to have the "domRef", the DOM
reference, of the corresponding opening element.
00:13:04 Now that I have all this information, I can actually open the popover.In order to do that, I'll just
say "oPopover" – I already have that instance –
00:13:14 and then I need to use the "openBy" method at the popover, and pass the opener in here.So
we have bound the popover to the corresponding object, the particular product we have just
clicked on,
00:13:31 and as the dialog is declaratively added to the page's dependent aggregation within the view, it
also gets access to the model the view has inherited from its component.
00:13:43 So we get the correct binding by asking the event for its source control, and the source control
for its own context binding, and then in turn asking the context binding for its path.
00:13:53 We can use this path in element binding for the popup as we have access to the model
anyway.We'll see this in the debugger in a minute.
00:14:03 We can actually now run our application.I need to reload this briefly.
00:14:19 Okay, I have an error here: "Cannot add direct child without default aggregation defined for
control sap.m.ResponsivePopover".
00:14:26 I need to fix this briefly because what has happened is that in my worklist view I forgot to add
the corresponding aggregation declaration to the responsive popover itself,
00:14:37 so I forgot to let the responsive popover know that the grid is actually going to the content
aggregation of the responsive popover.
00:14:45 So I just need to add that here: Something about the formatting is not perfect here, so I need
to change the formatting a bit, and now it should work.
00:15:00 So going back to my application...Okay, now you can see that the list appears again,
00:15:09 and when I click on one of those product IDs, that the popover opens and that it has an arrow
pointing to the corresponding opening element that we have seen.
00:15:20 When I click on a different one, you can see that the dimensions change accordingly, and I can
click outside to close the popover again.
00:15:32 When we have a look at the DOM now, we can see where the popover is actually added.So
when I open one popover and I have a look at the elements part within the developer tools,
00:15:46 I can see an area preserved for elements that are hidden when you open the view first.There's
an area called "sap-ui-static", in which the popover is placed.
00:16:05 When I scroll down here, you can see that it actually appears here.It is not a regular part of our
UI, and it will also not be added to the view DOM.
00:16:15 It is instead rendered in this special area in the DOM, which is reserved for these elements
which need to be hidden.This area is just a div appended to the body of the HTML page.
00:16:30 When we inspect our popover in the DOM, we can easily see that it ends up there with a
“visibility:hidden” inline style as soon as I close
00:16:43 Now we have added our popover to one view, but how about reusing it in another? Say we
want to reuse the popover in our object view.
00:16:53 The way it is implemented now, we would have to copy the complete code from the worklist
view and its controller to the object view and controller.
00:17:02 This is certainly not what we want. So how about using a fragment for the dialog itself? Let us
first briefly recap what you already know about fragments:
00:17:13 You have learned that fragments are lightweight UI parts – you could also say subtrees – that
can be defined similar to views. However, fragments do not have their own controllers, but can
get access to the controller of the surrounding view,
00:17:28 You know that a fragment can consist of one or multiple controls, and that when these controls
are embedded into a view, there is at runtime no trace of the fragment in the DOM.
00:17:41 When we use a dialog inside a fragment, we will create this fragment as a single-rooted
fragment.There will only be one control inside, which is the dialog itself.
00:17:52 When we do so, we can instantiate the fragment from the code, and directly access the control
methods at the instance of the fragment factory.
00:18:02 You can see this on this slide.A dialog in a fragment is instantiated here – you can see that the
fragment factory is involved here –
00:18:10 and then we can call its open method directly at the instance the fragment factory returns.Let
us have a look at how this works in our concrete sample application,
00:18:23 so I'll go back to my code here Let us create the fragment first and create a new file in the view
folder of our application.
00:18:32 You just need to right-click here again, then click on "New", "File", and we will call this file
"DetailPopover.fragment.xml".
00:18:48 Like in the last unit, we will start with the fragment definition again.So I'll start with the fragment
definition declaration here,
00:19:00 and as always I need to add some namespaces.Our default namespace will again be the
"sap.m" library.
00:19:10 Then we need the layout library as we also want to use our grid in here, so I will also add the
"xmlns:l" namespace for the "sap.ui.layout" library.
00:19:23 And then we also need to specify the core namespace as we are already using it for the
fragment definition here.So I need to add that here too,
00:19:34 and it just takes "sap.ui.core" here for this namespace.So when I close this again, I have my
fragment definition here.
00:19:47 Then we can fill the fragment with life, cutting the code for the responsive popover from the
worklist view, and pasting it into our fragment.
00:19:55 I'll briefly save this here, go to my worklist view, and then just cut out everything that belongs to
my responsive popover.I can also delete these two lines declaring the dependents aggregation
for my page here,
00:20:16 save this, and just paste the code for the responsive popover in here, and format it
correctly.Okay, that's all it takes for our fragment.
00:20:29 Next, we need to adapt the controller.We don’t want to create a new popover instance every
time we open the popover,
00:20:35 and actually it also makes sense to not instantiate the popover at all before it is required for the
first time. So we will implement a function that will do a lazy instantiation.
00:20:47 If there is no popover instance yet, we create one and store the instance at the controller.If
there is an instance, we just return what we have.
00:20:59 Let's go to our controller...and add the corresponding functionality.
00:21:06 In order to get access to the model, by the way, we need to add the popover instance as a
dependent to our view programmatically.
00:21:13 This will again provide access for the popover to the model and lifecycle of our view.I will
create this new function first as a private function, and I will call it "getPopover",
00:21:26 which will do the lazy instantiation for us.So it is going to be a function without any parameters
that need to go in there,
00:21:36 and I'll create this dialog, I'll just say: If there is there is no dialog at my controller yet,
00:21:45 so no instance under "this._oPopover", which has already been created here, then I actually
want my popover to be created,
00:21:59 and so I need to involve the fragment factory here.So I can say, okay in this case I want
"this._oPopover" to be whatever my fragment returns.
00:22:13 And I can invoke the fragment factory here by just typing "sap.ui.xmlfragment", I need to
specify its ID, which again is "opensap.manageproducts.view.DetailPopover" – "products" with
a small "p".
00:22:48 We only need to pass one more thing – the reference to the surrounding controllers – so I can
just type this in here.Now, as mentioned, we also need to add this to the dependents of our
view for the access to the model data.
00:23:09 I can do this by just calling "this.getView" on my controller, which will deliver the view instance
I'm currently looking at.Then I can just call "addDependent", and pass my popover instance
"this._oPopover" in there.
00:23:31 Of course what I also need to do is return the popover correspondingly.Okay, next we define
the actual new event handler,
00:23:47 so we need to have a look at our "onShowDetailPopover" function again, and we need to
adapt this correspondingly.
00:23:55 For instance, we need to adapt this line where we used to retrieve the popover by its ID.We
cannot do this anymore, but we now need to get this popover instance from our new function.
00:24:07 So instead of calling "this.byId" with the "dimensionsPopover" ID, I will say "this._oPopover"
and call the new private function that we have just created for the lazy instantiation.
00:24:21 Then we can still bind the popover to the element that has just opened it, so the part about the
binding context will remain the same.
00:24:32 Next, we need to open it at the current position, which will also have stayed the same, and we
could just leave the remaining lines in this event handler as they were.
00:24:44 So we have retrieved the "Popover" instance now, and we have bound it correctly, and we can
also open the popover.As mentioned, as this is a single-root fragment, we directly get the
control instance inside,
00:24:58 and hence we can just use the "openBy" method at the popover.So now we should be able to
run our application again.
00:25:06 Let me just close this part, so I need to reload it once.Then when I click on one of those
products IDs, you can see that we still get the popover,
00:25:18 just like when we had declared it in our view directly.Now we can easily reuse our fragment in
the object view for instance.
00:25:28 Just copying the controller code to another view's controller.Let us reuse the popover now in
the object view.
00:25:36 I simply go to my worklist controller again and copy over the two functions that we have
created here.And when I now open the object controller, and scroll down a bit to the event
handler section,
00:25:50 I will add the new methods down below the last event handler that has already been specified.I
can save this here, then we need to add some opener, which should trigger the popover from
the object view.
00:26:04 So I need to open the object view here.Then I will simply set the object header to "titleActive"...
00:26:33 and I will also give it the "titlePress" event again, which will point to the event handler
"onShowDetailPopover" that we have just copied over.
00:26:53 Setting the "titleActive" property to "true" will allow us to trigger the event handler method we
have already defined.Now we have the same fragment for the dimensions reused in both
worklist and object view.
00:27:06 So when we now rerun our application again, and we switch to the object view for one of the
products,
00:27:14 you can see that this title is actually clickable, and when I click on that, I can also open the
"dimensions" popover.
00:27:22 So as you can see, both views are conveniently using the same popover fragment now.This
concludes our unit on implementing dialogs, and this was also the last unit for the third week of
our course.
00:27:35 Next week, you will learn how to master SAPUI5, digging deeper into routing, CRUD features,
and debugging and testing your application.
00:27:45 My name is Christiane, and I wish you good luck with your assignments. Looking forward to
seeing you in the forums!
00:27:51 Thank you.
www.sap.com