diff --git a/packages/databinding/steps/01/README.md b/packages/databinding/steps/01/README.md index 8f9a3c61a..249afb758 100644 --- a/packages/databinding/steps/01/README.md +++ b/packages/databinding/steps/01/README.md @@ -1,15 +1,15 @@ -# Step 1: No Data Binding +## Step 1: No Data Binding In this step, we create a basic application and simply place some text on the screen using a standard `sap.m.Text` control. The text in this control is a hard-coded part of the control's definition; therefore, this is not an example of data binding! -## Preview +### Preview ![The browser shows the text "Hi, my name is Harry Hawk"](assets/Tutorial_Data_Binding_Step_1_6d391d5.png "The browser shows the text "Hi, my name is Harry Hawk"") You can view this step live: [πŸ”— Live Preview of Step 1](https://ui5.github.io/tutorials/databinding/build/01/index-cdn.html). -## Setup +### Setup Open a terminal and install UI5 Tooling globally on your machine by executing the following command: @@ -17,11 +17,11 @@ Open a terminal and install UI5 Tooling globally on your machine by executing th npm install --global @ui5/cli ``` -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 1](https://ui5.github.io/tutorials/databinding/databinding-step-01.zip) (TS)[πŸ“₯ Download step 1](https://ui5.github.io/tutorials/databinding/databinding-step-01-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -36,7 +36,7 @@ webapp/ 2. Create a new file called `package.json` which will enable you to execute commands and consume packages from the [npm registry](https://www.npmjs.com/) via the npm command line interface. Enter the following content: -## package.json \(New\) +### package.json \(New\) ```json { @@ -55,7 +55,7 @@ webapp/ 4. Create a new HTML file named `index.html` in your webapp folder and enter the following content: -## webapp/index.html \(New\) +### webapp/index.html \(New\) ```html @@ -84,7 +84,7 @@ webapp/ 5. Create a new file named `manifest.json` in the webapp folder; it's also known as the "app descriptor". All application-specific configuration options which we'll introduce in this tutorial will be added to this file. Enter the following content: -## webapp/manifest.json \(New\) +### webapp/manifest.json \(New\) ```json { @@ -129,7 +129,7 @@ webapp/ 6. Create a new file named `Component.ts/.js` in the webapp folder. Enter the following content: -## `webapp/Component.ts/.js` \(New\) +### webapp/Component.ts/.js \(New\) ```ts // webapp/Component.ts @@ -162,7 +162,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { 7. Create a new folder named `view` in the webapp folder. Then, create a new file `App.view.xml` within the `view` folder. We start by placing the `sap.m.Text` control into the XML view. Since the value of the control's text property is hard-coded, it doesn't relate to any data that might exist within a model object. Therefore, data binding is **not** used here. -## webapp/view/App.view.xml \(New\) +### webapp/view/App.view.xml \(New\) ```xml [πŸ“₯ Download step 2](https://ui5.github.io/tutorials/databinding/databinding-step-02.zip) (TS)[πŸ“₯ Download step 2](https://ui5.github.io/tutorials/databinding/databinding-step-02-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -49,7 +49,7 @@ webapp/ 1. Create a new folder named `model` in the `webapp` folder. In this folder, create a file called `data.json` with the following content: -## webapp/model/data.json \(New\) +### webapp/model/data.json \(New\) ```json { @@ -59,7 +59,7 @@ webapp/ 2. Create a new JSON model in the `manifest.json` and set its path via a URI. This binds the model object to the app component and makes it globally available to all controls used within the application. -## webapp/manifest.json +### webapp/manifest.json ```json { diff --git a/packages/databinding/steps/03/README.md b/packages/databinding/steps/03/README.md index 439e5e5c9..5fc1dff44 100644 --- a/packages/databinding/steps/03/README.md +++ b/packages/databinding/steps/03/README.md @@ -1,19 +1,19 @@ -# Step 3: Create Property Binding +## Step 3: Create Property Binding Although there is no visible difference, the text on the screen is now derived from model data. -## Preview +### Preview ![The browser shows the text "Hi, my name is Harry Hawk"](assets/Tutorial_Data_Binding_Step_1_6d391d5.png "The browser shows the text "Hi, my name is Harry Hawk"") You can view this step live: [πŸ”— Live Preview of Step 3](https://ui5.github.io/tutorials/databinding/build/03/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 3](https://ui5.github.io/tutorials/databinding/databinding-step-03.zip) (TS)[πŸ“₯ Download step 3](https://ui5.github.io/tutorials/databinding/databinding-step-03-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -28,7 +28,7 @@ webapp/ Assign the `text` property of the `sap.m.Text` control to the value `{/greetingText}`. The curly brackets enclosing a binding path \(binding syntax\) are automatically interpreted as a binding. These binding instances are called property bindings. In this scenario, the control's `text` property is bound to the `greetingText` property at the root of the default model. The slash \(`/`\) at the beginning of the binding path signifies an absolute binding path. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 4](https://ui5.github.io/tutorials/databinding/databinding-step-04.zip) (TS)[πŸ“₯ Download step 4](https://ui5.github.io/tutorials/databinding/databinding-step-04-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -30,7 +30,7 @@ webapp/ Replace the content of the `App.view.xml` file with the following content: -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 5](https://ui5.github.io/tutorials/databinding/databinding-step-05.zip) (TS)[πŸ“₯ Download step 5](https://ui5.github.io/tutorials/databinding/databinding-step-05-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -30,7 +30,7 @@ webapp/ Insert the highlighted code into the `Component.ts/.js` file. The `init` function calls the init function of its parent, retrieves the default model instance bound to the component, and sets the default binding mode to one-way data binding. -## `webapp/Component.ts/.js` +### webapp/Component.ts/.js ```ts // webapp/Component.ts diff --git a/packages/databinding/steps/06/README.md b/packages/databinding/steps/06/README.md index 2e282a863..760c6bda7 100644 --- a/packages/databinding/steps/06/README.md +++ b/packages/databinding/steps/06/README.md @@ -1,23 +1,23 @@ -# Step 6: Resource Models +## Step 6: Resource Models Business applications often require language-specific \(translatable\) text used as labels and descriptions on the user interface. The example we used at the start of this tutorial was quite simplistic as we stored language-specific text directly in a JSON model object. Generally speaking, unless language-specific text comes directly from a back-end system, it's not considered good programming practice to put translatable texts directly into a model. So, let's fix this by placing all translatable texts \(such as field labels\) into a resource bundle. -## Preview +### Preview -### The texts are now derived from a resource model \(No visual change to last step\) +#### The texts are now derived from a resource model \(No visual change to last step\) ![The texts are now derived from a resource model (No visual change to last step)](assets/Tutorial_Data_Binding_Step_4_61d68f1.png "The texts are now derived from a resource model (No visual change to last step)") You can view this step live: [πŸ”— Live Preview of Step 6](https://ui5.github.io/tutorials/databinding/build/06/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 6](https://ui5.github.io/tutorials/databinding/databinding-step-06.zip) (TS)[πŸ“₯ Download step 6](https://ui5.github.io/tutorials/databinding/databinding-step-06-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -36,7 +36,7 @@ Create a new entry in the `manifest.json` file under the `models` entry as shown Also add the `i18n` property to the `sap.app` section and modify the `title` and `description` property to use the corresponding texts from the `i18n.properties` as shown below. -## webapp/manifest.json +### webapp/manifest.json ```json ... @@ -89,7 +89,7 @@ Also add the `i18n` property to the `sap.app` section and modify the `title` and Update the `i18n.properties` and add the code shown below. -## webapp/i18n/i18n.properties \(New\) +### webapp/i18n/i18n.properties \(New\) ```properties # App Descriptor @@ -111,7 +111,7 @@ Language-specific text stored in resource models obeys the Java convention for i Modify the data binding for the panel header and the labels in `App.view.xml` to include the model name. Note that a "greater than" character separates the model name and the property name. Also, i18n property names **must not** start with a slash character. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 7](https://ui5.github.io/tutorials/databinding/databinding-step-07.zip) (TS)[πŸ“₯ Download step 7](https://ui5.github.io/tutorials/databinding/databinding-step-07-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -31,7 +31,7 @@ webapp/ └── manifest.json ``` -## webapp/i18n/i18n\_de.properties \(New\) +### webapp/i18n/i18n\_de.properties \(New\) In the `i18n` folder, duplicate the `i18n.properties` file and rename its copy to `i18n`**`_de`**`.properties`. Replace the English text with the German text provided below. The suffix `de` represents the locale for the German language. Since the `de` locale is already set in the `supportedLocales` configuration of the `manifest.json`, it will be taken into account. diff --git a/packages/databinding/steps/08/README.md b/packages/databinding/steps/08/README.md index 2ff88b688..adcf11ec7 100644 --- a/packages/databinding/steps/08/README.md +++ b/packages/databinding/steps/08/README.md @@ -1,21 +1,21 @@ -# Step 8: Binding Paths: Accessing Properties in Hierarchically Structured Models +## Step 8: Binding Paths: Accessing Properties in Hierarchically Structured Models In Step 6 , we stated that the fields in a resource model are arranged in a flat structure; in other words, there is no hierarchy of properties. However, this is only true for resource models. The properties within JSON and OData models are usually arranged in a hierarchical structure. So, let's explore how to reference fields in a hierarchically structured model object. -## Preview +### Preview -### A second panel with address data is added +#### A second panel with address data is added ![A second panel with address data is added](assets/Tutorial_Data_Binding_Step_8_12705f5.png "A second panel with address data is added") You can view this step live: [πŸ”— Live Preview of Step 8](https://ui5.github.io/tutorials/databinding/build/08/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 8](https://ui5.github.io/tutorials/databinding/databinding-step-08.zip) (TS)[πŸ“₯ Download step 8](https://ui5.github.io/tutorials/databinding/databinding-step-08-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -33,7 +33,7 @@ webapp/ In the `data.json` file, add an additional sub-object named `address`. This object has four properties: `street`, `city`, `zip`, and `country`. -## webapp/model/data.json +### webapp/model/data.json ```json { @@ -55,7 +55,7 @@ The `text` property of the `Label` element is bound to the i18n resource bundle The `htmlText` property of the `FormattedText` element is bound to four JSON model properties: `/address/street`, `/address/zip`, `/address/city`, and `/address/country`. You can achieve the resulting address format by separating each one of these JSON model property references with a hard-coded newline character. Note that `zip` and `city` are separated by a space. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 9](https://ui5.github.io/tutorials/databinding/databinding-step-09.zip) (TS)[πŸ“₯ Download step 9](https://ui5.github.io/tutorials/databinding/databinding-step-09-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -35,7 +35,7 @@ webapp/ Create a new folder named `controller` within your `webapp` folder as a general location for all controller files for this app. Next, create a new file named `App.controller.ts/.js` with the following content: -## `webapp/controller/App.controller.ts/.js` \(New\) +### webapp/controller/App.controller.ts/.js \(New\) ```ts // webapp/controller/App.controller.ts @@ -88,7 +88,7 @@ In the `formatMail` function, we use the `sap.m.URLHelper.normalizeEmail` functi Enhance the `App.view.xml` file as shown below: -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 10](https://ui5.github.io/tutorials/databinding/databinding-step-10.zip) (TS)[πŸ“₯ Download step 10](https://ui5.github.io/tutorials/databinding/databinding-step-10-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -35,7 +35,7 @@ webapp/ Add two new JSON model properties, `salesAmount` and `currencyCode`, to the `data.json` file. -## webapp/model/data.json +### webapp/model/data.json ```json { @@ -55,7 +55,7 @@ Add two new JSON model properties, `salesAmount` and `currencyCode`, to the `dat Add a `sap.ui.layout.HorizontalLayout` to the content of the second `sap.m.Panel` within `App.view.xml` file. Move the existing `sap.ui.layout.VerticalLayout` to the default aggregation of the new `sap.ui.layout.HorizontalLayout`. Finally, add a second `sap.ui.layout.VerticalLayout`, containing a `sap.m.Label` and a `sap.m.Input` control, to the `sap.ui.layout.HorizontalLayout`. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 11](https://ui5.github.io/tutorials/databinding/databinding-step-11.zip) (TS)[πŸ“₯ Download step 11](https://ui5.github.io/tutorials/databinding/databinding-step-11-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -33,7 +33,7 @@ webapp/ └── manifest.json ``` -## webapp/manifest.json +### webapp/manifest.json To generally enable validation in the app, add the `handleValidation` property into the `sap.ui5` section of the `manifest.json` file as shown below. diff --git a/packages/databinding/steps/12/README.md b/packages/databinding/steps/12/README.md index 8ff778bad..a1d5e77a0 100644 --- a/packages/databinding/steps/12/README.md +++ b/packages/databinding/steps/12/README.md @@ -1,5 +1,5 @@ -# Step 12: Aggregation Binding Using Templates +## Step 12: Aggregation Binding Using Templates Aggregation binding, also known as "list binding", lets a control bind to a list within the model data. This binding allows relative binding to the list entries by its child controls. @@ -9,19 +9,19 @@ The system automatically creates as many child controls as are needed to display - It uses a factory function to generate the correct control for each bound list entry, based on the data received at runtime. -## Preview +### Preview -### A third panel with a list of products is displayed +#### A third panel with a list of products is displayed ![A third panel with a list of products is displayed](assets/Tutorial_Data_Binding_Step_12_1642433.png "A third panel with a list of products is displayed") You can view this step live: [πŸ”— Live Preview of Step 12](https://ui5.github.io/tutorials/databinding/build/12/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 12](https://ui5.github.io/tutorials/databinding/databinding-step-12.zip) (TS)[πŸ“₯ Download step 12](https://ui5.github.io/tutorials/databinding/databinding-step-12-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -42,7 +42,7 @@ webapp/ Add a new entry named `products` to the `models` entry under `sap.ui5` in the `manifest.json` file: -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -78,7 +78,7 @@ Add a new entry named `products` to the `models` entry under `sap.ui5` in the `m Create a new file named `Products.json` in the `model` folder. Enter the data for the products: -## webapp/model/Products.json \(New\) +### webapp/model/Products.json \(New\) ```json { @@ -149,7 +149,7 @@ Create a new file named `Products.json` in the `model` folder. Enter the data fo In the `App.view.xml` file, add a new panel with an `sap.m.List` control containing the `sap.m.ObjectListItem` template control as shown below. Note that the template control is only present once in the XML view. It's automatically cloned for each entry in the products' JSON model. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 13](https://ui5.github.io/tutorials/databinding/databinding-step-13.zip) (TS)[πŸ“₯ Download step 13](https://ui5.github.io/tutorials/databinding/databinding-step-13-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -36,7 +36,7 @@ webapp/ In the `App.view.xml` file, add a `press` event handler to the items in the list. Below the panel with the list, add a new panel with an `sap.m.SimpleForm`. To populate the form with data, we bind the entire panel to the path of the element you clicked in the list. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml ... @@ -109,7 +109,7 @@ In the `App.view.xml` file, add a `press` event handler to the items in the list In the controller, add a new function `onItemSelected`, which binds the newly created panel to the correct item whenever it's pressed. -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -152,7 +152,7 @@ sap.ui.define(["sap/ui/core/mvc/Controller", "sap/m/library", "sap/ui/model/type Lastly, add the new texts to the `i18n.properties` and `i18n_de.properties` files. -## webapp/i18n/i18n.properties +### webapp/i18n/i18n.properties ```properties ... @@ -174,7 +174,7 @@ Discontinued=Discontinued ``` -## webapp/i18n/i18n\_de.properties +### webapp/i18n/i18n\_de.properties ```properties # Screen titles diff --git a/packages/databinding/steps/14/README.md b/packages/databinding/steps/14/README.md index e6d601f2c..709e1cb65 100644 --- a/packages/databinding/steps/14/README.md +++ b/packages/databinding/steps/14/README.md @@ -1,21 +1,21 @@ -# Step 14: Expression Binding +## Step 14: Expression Binding An expression binding lets you display a calculated value on the screen, which is derived from values found in a model object. This feature allows you to insert simple formatting or calculations directly into the data binding string. In this example, we're changing the color of the price depending on whether it's above or below a certain threshold. The threshold value is stored in the JSON model. -## Preview +### Preview -### Prices are color-coded depending on a selected threshold +#### Prices are color-coded depending on a selected threshold ![Prices are color-coded depending on a selected threshold](assets/Tutorial_Data_Binding_Step_14_b9fb758.png "Prices are color-coded depending on a selected threshold") You can view this step live: [πŸ”— Live Preview of Step 14](https://ui5.github.io/tutorials/databinding/build/14/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 14](https://ui5.github.io/tutorials/databinding/databinding-step-14.zip) (TS)[πŸ“₯ Download step 14](https://ui5.github.io/tutorials/databinding/databinding-step-14-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -36,7 +36,7 @@ webapp/ Add a new property called `priceThreshold` with a value of 20 to the `data.json` file. -## webapp/model/data.json +### webapp/model/data.json ```json { @@ -57,7 +57,7 @@ Add a new property called `priceThreshold` with a value of 20 to the `data.json` In the `App.view.xml` file, add a new `numberState` property to the `ObjectListItem` element within the `List`. The value of this property is an expression that gets evaluated for each item. The expression compares each invoice value against the price threshold and returns a number state based on the result. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml ... diff --git a/packages/databinding/steps/15/README.md b/packages/databinding/steps/15/README.md index 13ea4d672..5c0d5b30d 100644 --- a/packages/databinding/steps/15/README.md +++ b/packages/databinding/steps/15/README.md @@ -1,21 +1,21 @@ -# Step 15: Aggregation Binding Using a Factory Function +## Step 15: Aggregation Binding Using a Factory Function Instead of using a single hard-coded template control, we now opt for a factory function to generate different controls based on the data received at runtime. This approach is much more flexible and allows for the display of complex or heterogeneous data. -## Preview +### Preview -### A different type of list item is displayed for a discontinued product +#### A different type of list item is displayed for a discontinued product ![A different type of list item is displayed for a discontinued product](assets/Tutorial_Data_Binding_Step_15_db27ba8.png "A different type of list item is displayed for a discontinued product") You can view this step live: [πŸ”— Live Preview of Step 15](https://ui5.github.io/tutorials/databinding/build/15/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 15](https://ui5.github.io/tutorials/databinding/databinding-step-15.zip) (TS)[πŸ“₯ Download step 15](https://ui5.github.io/tutorials/databinding/databinding-step-15-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -38,7 +38,7 @@ webapp/ Create a `ProductSimple.fragment.xml` file in the `view` folder. Here, define an `sap.m.StandardListItem` that is used when the stock level is zero and the product is discontinued. In this simple use case, you only need to define a warning icon and a "Product Discontinued" message in the `info` property. -## webapp/view/ProductSimple.fragment.xml \(New\) +### webapp/view/ProductSimple.fragment.xml \(New\) ```xml πŸ“ > The content of the `localService` folder will not be changed in this tutorial. The `i18n` folder will always contain the `i18n.properties` file only. Therefore, we will show both subfolders collapsed in the following steps. -## The Initial App +### The Initial App With the downloaded coding, you have an initial app with recommended settings that provides the basic features of an OpenUI5 app: diff --git a/packages/navigation/steps/02/README.md b/packages/navigation/steps/02/README.md index 2c07f0221..224db8b27 100644 --- a/packages/navigation/steps/02/README.md +++ b/packages/navigation/steps/02/README.md @@ -1,20 +1,20 @@ -# Step 2: Enable Routing +## Step 2: Enable Routing In this step we will modify the app and introduce routing. Instead of having the home page of the app hard coded we will configure a router to wire multiple views together when our app is called. The routing configuration controls the application flow when the user triggers a navigation action or opens a link to the application directly. -## Preview +### Preview -### Views are wired together using the router +#### Views are wired together using the router ![Views are wired together using the router](assets/Tutorial_Navigation_and_Routing_Step_02a.png "Views are wired together using the router") You can view this step live: [πŸ”— Live Preview of Step 2](https://ui5.github.io/tutorials/navigation/build/02/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 2](https://ui5.github.io/tutorials/navigation/navigation-step-02.zip) (TS)[πŸ“₯ Download step 2](https://ui5.github.io/tutorials/navigation/navigation-step-02-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -38,7 +38,7 @@ webapp/ └── manifest.json ``` -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -112,7 +112,7 @@ Single-page applications based on OpenUI5 can use a so-called β€œrouter” to di > πŸ“ > As of OpenUI5 version 1.30, we recommend that you define the routing in the `manifest.json` descriptor file using routes and targets. In older versions of OpenUI5, the routing configuration had to be done directly in the metadata section of the component, and with different syntax. -## `webapp/Component.ts/.js` +### webapp/Component.ts/.js ```ts // webapp/Component.ts @@ -160,7 +160,7 @@ sap.ui.define(["sap/ui/core/UIComponent"], function (UIComponent) { We override the `init` function and call the parent’s `init` function first. We get a reference to the router and call `initialize()`on it. The router is instantiated automatically with the configuration loaded in the descriptor. The routing events and our configuration in the descriptor are now automatically enabled in the app. Running the app at this point would lead to an error, because the home view is not implemented yet. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml homePageTitle`, you can use data binding just the way you are used to it. -## `webapp/controller/Home.controller.ts/.js` \(New\) +### webapp/controller/Home.controller.ts/.js \(New\) ```ts // webapp/controller/Home.controller.ts @@ -228,7 +228,7 @@ Create a file `Home.controller.ts` in the `webapp/controller` folder. The contro > > Based on the routing configuration, you define the navigation between pages and pass parameters to the target views. -## Conventions +### Conventions - Configure the router in the `manifest.json` descriptor file diff --git a/packages/navigation/steps/03/README.md b/packages/navigation/steps/03/README.md index 3f8395045..189cdf197 100644 --- a/packages/navigation/steps/03/README.md +++ b/packages/navigation/steps/03/README.md @@ -1,20 +1,20 @@ -# Step 3: Catch Invalid Hashes +## Step 3: Catch Invalid Hashes Sometimes it is important to display an indication that the requested resource was not found. To give you an example: If a user tries to access an invalid pattern which does not match any of the configured routes, the user is notified that something went wrong. You might also know this as a β€œ404” or *Not Found Page* from traditional web pages. In this step, we will implement a feature that detects invalid hashes and visualizes this in a nice way. -## Preview +### Preview -### Not Found page +#### Not Found page ![Not Found page](assets/Tutorial_Navigation_and_Routing_Step_03.png "Not Found page") You can view this step live: [πŸ”— Live Preview of Step 3](https://ui5.github.io/tutorials/navigation/build/03/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 3](https://ui5.github.io/tutorials/navigation/navigation-step-03.zip) (TS)[πŸ“₯ Download step 3](https://ui5.github.io/tutorials/navigation/navigation-step-03-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -40,7 +40,7 @@ webapp/ └── manifest.json ``` -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -84,7 +84,7 @@ webapp/ Let’s extend the routing configuration in the descriptor by adding a `bypassed` property and setting its `target` to `notFound`. This configuration tells the router to display the `notFound` target in case no route was matched to the current hash. Next, we add a `notFound` target to the `bypassed` section. The `notFound` target simply configures a `NotFound` view with a `show` transition. -## webapp/view/NotFound.view.xml \(New\) +### webapp/view/NotFound.view.xml \(New\) ```xml [πŸ“₯ Download step 4](https://ui5.github.io/tutorials/navigation/navigation-step-04.zip) (TS)[πŸ“₯ Download step 4](https://ui5.github.io/tutorials/navigation/navigation-step-04-js.zip) (JS). -## webapp/view/NotFound.view.xml +### webapp/view/NotFound.view.xml ```xml [πŸ“₯ Do In the `NotFound` view, we set the property `showNavButton` of the `Page` control to `true` which automatically displays the *Back* button. We also add an event handler function `onNavBack` to the `navButtonPress` event of the control. The `onNavBack` function will handle the actual back navigation. We could directly add this function to the `NotFound` view’s controller. However, we are smart enough to anticipate that we might need the same handler function for different views. DRY \(β€œDon’t Repeat Yourself”\) is the right approach for us, so let’s create a `BaseController` from which all other controllers will inherit. -## `webapp/controller/BaseController.ts/.js` \(New\) +### webapp/controller/BaseController.ts/.js \(New\) ```ts // webapp/controller/BaseController.ts @@ -130,7 +130,7 @@ The third parameter of `navTo("appHome", {}, true /*no history*/);` has the valu > πŸ“ > In OpenUI5 there are multiple options to reuse code. We recommend to use a base controller for such helper methods because this allows us to decoratively use the `onNavBack` handler directly in any XML view without adding additional code to the controller. Our base controller is an abstract controller that will not be instantiated in any view. Therefore, the naming convention `*.controller.ts` does not apply, and we can just name the file `BaseController.ts`. By not using the naming convention `*.controller.ts` we can even prevent any unintentional usage in views. -## `webapp/controller/NotFound.controller.ts/.js` +### webapp/controller/NotFound.controller.ts/.js ```ts // webapp/controller/NotFound.controller.ts @@ -163,7 +163,7 @@ In order to reuse the base controller implementation, we have to change the depe At this point you can open `index.html#/thisIsInvalid` in your browser and press the *Back* button to see what happens. You will be redirected to the app’s home page that is matched by the route `appHome` as you opened the *Not Found* page with an invalid hash. If you change the hash to something invalid when you are on the home page of the app, you will also go to the *Not Found* page but with a history entry. When you press back, you will get to the home page again, but this time with a native history navigation. -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -194,7 +194,7 @@ sap.ui.define(["ui5/tutorial/navigation/controller/BaseController"], function (B To be consistent, we will now adjust all of our controllers to extend to inherit from the `BaseController`. Change the `App` controller as described above. -## `webapp/controller/Home.controller.ts/.js` +### webapp/controller/Home.controller.ts/.js ```ts // webapp/controller/Home.controller.ts @@ -223,7 +223,7 @@ The same applies to our `Home` controller, we now also inherit from the `BaseCon > πŸ“ > In this step we have added the *Back* button. The user can always use the browser’s native *Back* button as well. Each app can freely configure the behavior of the *Back* button. However, there is no clean way to apply the same logic for the browser’s *Back* button in single-page applications. Tweaking the browser history or using other quirks for cancelling backward or forward navigation is not recommended due to the implementation details of the browsers. The browser’s *Back* button always uses the browser history while the *Back* button of the app can make use of the browser history **or** can implement its own navigation logic. Make sure to understand this difference and only control the *Back* button inside the app. -## Conventions +### Conventions - Implement a global `onNavBack` handler for back navigation in your app diff --git a/packages/navigation/steps/05/README.md b/packages/navigation/steps/05/README.md index f460c25bf..13e545fe3 100644 --- a/packages/navigation/steps/05/README.md +++ b/packages/navigation/steps/05/README.md @@ -1,4 +1,4 @@ -# Step 5: Display a Target Without Changing the Hash +## Step 5: Display a Target Without Changing the Hash In this step, you will learn more about targets and how to display a target from the routing configuration manually. @@ -6,19 +6,19 @@ We will display the *Not Found* target from the previous step without changing t Fortunately, we can extend our app and offer an easy solution. There are some use cases that should not be persisted in the URL but just be triggered by the application logic if needed. A target is a navigation-related configuration for a view and we can display targets manually without referencing them in a navigation route. Good examples for this are temporary errors, switching to an edit page for a business object, or going to a *Settings* page. Sometimes you will also have to implement a way back manually. -## Preview +### Preview -### The new Home page with a navigation button +#### The new Home page with a navigation button ![The new Home page with a navigation button](assets/Tutorial_Navigation_and_Routing_Step_05.png "The new Home page with a navigation button") You can view this step live: [πŸ”— Live Preview of Step 5](https://ui5.github.io/tutorials/navigation/build/05/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 5](https://ui5.github.io/tutorials/navigation/navigation-step-05.zip) (TS)[πŸ“₯ Download step 5](https://ui5.github.io/tutorials/navigation/navigation-step-05-js.zip) (JS). -## webapp/view/Home.view.xml +### webapp/view/Home.view.xml ```xml [πŸ“₯ Do We start by changing the `Button` control from the home view. When the button is pressed, the `onDisplayNotFound` handler is called. -## `webapp/controller/Home.controller.ts/.js` +### webapp/controller/Home.controller.ts/.js ```ts // webapp/controller/Home.controller.ts @@ -84,7 +84,7 @@ If you now call the app and press the *Display Not Found* button you see that th When pressing the app’s *Back* button, the `onNavBack` from the previous step is called. It detects that there is no previous hash and therefore tries to navigate to the `appHome` route again. The router is smart enough to detect that the current hash did not change and therefore skips the navigation to the route. Fortunately, there is an easy workaround for us. However, we need to touch the `Home` controller again. -## `webapp/controller/Home.controller.ts/.js` \(Changed Again\) +### webapp/controller/Home.controller.ts/.js \(Changed Again\) ```ts // webapp/controller/Home.controller.ts @@ -123,7 +123,7 @@ sap.ui.define(["ui5/tutorial/navigation/controller/BaseController"], function (B This time we pass on a data object as the second parameter for the display method which contains the name of the current target; the one from which we navigate to the `notFound` target. We decide to choose the key `fromTarget` but since it is a custom configuration object any other key would be fine as well. -## `webapp/controller/NotFound.controller.ts/.js` +### webapp/controller/NotFound.controller.ts/.js ```ts // webapp/controller/NotFound.controller.ts @@ -199,7 +199,7 @@ From the router reference we can fetch a reference to the `notFound` target. Eac Similar to OpenUI5 controls, targets define API methods and events that can be attached. We attach a display event handler and save the configuration that was received as the event parameter `data` in an internal controller variable `this.data`. This also includes the `fromTarget` information in case the caller passed it on. However, we now have to override the base controller’s `onNavBack` implementation to change the behavior a bit. We add a special case for our *Back* functionality in case the `fromTarget` property has been passed on. If specified, we simply display the target defined as `fromTarget` manually the same way we actually called the `notFound` target manually. Otherwise we just call the `onNavBack` implementation in the `BaseController`. -## webapp/i18n/i18n.properties +### webapp/i18n/i18n.properties ```properties ... @@ -210,7 +210,7 @@ Add the new property to the `i18n.properties` file. When we now click the *Back* button, it works as expected and brings us back to the overview page, also when the *Not Found* view is displayed manually. -## Conventions +### Conventions - Display targets manually if you want to trigger a navigation without changing the hash diff --git a/packages/navigation/steps/06/README.md b/packages/navigation/steps/06/README.md index 04394e326..ad2afa026 100644 --- a/packages/navigation/steps/06/README.md +++ b/packages/navigation/steps/06/README.md @@ -1,24 +1,24 @@ -# Step 6: Navigate to Routes with Hard-Coded Patterns +## Step 6: Navigate to Routes with Hard-Coded Patterns In this step, we'll create a second button on the home page, with which we can navigate to a simple list of employees. This example illustrates how to navigate to a route that has a hard-coded pattern. -## Preview +### Preview -### Show Employee List button on the Home page +#### Show Employee List button on the Home page ![Show Employee List button on the Home page](assets/Tutorial_Navigation_and_Routing_Step_06a.png "Show Employee List button on the Home page") -### Employee list with Back button +#### Employee list with Back button ![Employee list with Back button](assets/Tutorial_Navigation_and_Routing_Step_06b.png "Employee list with Back button") You can view this step live: [πŸ”— Live Preview of Step 6](https://ui5.github.io/tutorials/navigation/build/06/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 6](https://ui5.github.io/tutorials/navigation/navigation-step-06.zip) (TS)[πŸ“₯ Download step 6](https://ui5.github.io/tutorials/navigation/navigation-step-06-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -49,7 +49,7 @@ webapp/ └── manifest.json ``` -## webapp/view/Home.view.xml +### webapp/view/Home.view.xml ```xml [πŸ“₯ Download step 7](https://ui5.github.io/tutorials/navigation/navigation-step-07.zip) (TS)[πŸ“₯ Download step 7](https://ui5.github.io/tutorials/navigation/navigation-step-07-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -57,7 +57,7 @@ webapp/ └── manifest.json ``` -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -133,7 +133,7 @@ The following hashes would match in our case: `employees/2`, `employees/7`, `emp Next, we have to create the view `employees.Employee`; for better illustration the `path` is not specified this time. -## webapp/view/employee/Employee.view.xml \(New\) +### webapp/view/employee/Employee.view.xml \(New\) ```xml Requiring `sap/ui/layout/form/ResponsiveGridLayout` is needed because we use the `ResponsiveGridLayout` as `layout` for the `sap/ui/layout/form/SimpleForm`. > The `sap/ui/layout/form/SimpleForm` requires the configured layout, in case it's not done by the consumer but this may cause an additional rendering cycle if rendering starts before the layout finished loading. -## `webapp/controller/employee/Employee.controller.ts/.js` \(New\) +### webapp/controller/employee/Employee.controller.ts/.js \(New\) ```ts // webapp/controller/employee/Employee.controller.ts @@ -291,7 +291,7 @@ We also add an event handler to the `change` event as a private function `_onBin > πŸ“ > Instead of calling `attachMatched(…)` on a route we could also call `attachRouteMatched(…)` directly on the router. However, the event for the latter is fired for every matched event of any route in the whole app. We don’t use the latter because we would have to implement an additional check for making sure that current route is the route that has been matched. We want to avoid this extra overhead and register on the route instead. -## webapp/view/employee/EmployeeList.view.xml +### webapp/view/employee/EmployeeList.view.xml ```xml [πŸ“₯ Download step 8](https://ui5.github.io/tutorials/navigation/navigation-step-08.zip) (TS)[πŸ“₯ Download step 8](https://ui5.github.io/tutorials/navigation/navigation-step-08-js.zip) (JS). -### Folder structure for this step +#### Folder structure for this step ```text webapp/ @@ -58,7 +58,7 @@ webapp/ └── manifest.json ``` -## webapp/view/employee/Employee.view.xml +### webapp/view/employee/Employee.view.xml ```xml > You can also implement your own transitions and add it to a control that extends `sap.m.NavContainer` \(for example, `sap.m.App` or `sap.m.SplitApp`\). For more information, see the [API Reference: `NavContainer`](https://sdk.openui5.org/#/api/sap.m.NavContainer). -## webapp/view/employee/Resume.view.xml \(New\) +### webapp/view/employee/Resume.view.xml \(New\) ```xml @@ -410,7 +410,7 @@ Create a file `ResumeProjects.view.xml` in the `webapp/view/employee` folder. Th > πŸ“ > For more complex applications, the performance is significantly increased if parts of the UI are only loaded when the user is actively selecting it. In this example, the view is always loaded even though the user never decided to display the project information. In the next steps, we will extend the UI so that the content is loaded β€œlazy” by OpenUI5 only when the filter item is clicked. The back-end service will fetch the data only on request and the UI will only have to be updated with the selected data instead of loading all data. -## webapp/i18n/i18n.properties +### webapp/i18n/i18n.properties ```properties ... diff --git a/packages/navigation/steps/09/README.md b/packages/navigation/steps/09/README.md index 69ddcdc06..46847eb44 100644 --- a/packages/navigation/steps/09/README.md +++ b/packages/navigation/steps/09/README.md @@ -1,22 +1,22 @@ -# Step 9: Allow Bookmarkable Tabs with Optional Query Parameters +## Step 9: Allow Bookmarkable Tabs with Optional Query Parameters The `resume` view contains four tabs as we have seen in the previous step of this tutorial. However, when the user navigates to the `resume` page, only the first tab is displayed initially. Navigating directly to a specific tab or bookmarking a tab is not yet supported in our current app. In this step, we implement a bookmarking feature by enabling deep linking to tabs with optional query parameters. A deep link is basically a link that directly references a deeper structure and parameters of the app in the URL. It is often bookmarked or shared to have a convenient entry point into the app for a certain task or action. The selected tab should be reflected in the URL but the tab can also be omitted, for example, when we initially navigate to the resume page. -## Preview +### Preview -### Deep link to allow bookmarkable tabs +#### Deep link to allow bookmarkable tabs ![Deep link to allow bookmarkable tabs](assets/Tutorial_Navigation_and_Routing_Step_09.png "Deep link to allow bookmarkable tabs") You can view this step live: [πŸ”— Live Preview of Step 9](https://ui5.github.io/tutorials/navigation/build/09/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 9](https://ui5.github.io/tutorials/navigation/navigation-step-09.zip) (TS)[πŸ“₯ Download step 9](https://ui5.github.io/tutorials/navigation/navigation-step-09-js.zip) (JS). -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -73,7 +73,7 @@ This allows URLs like `webapp/index.html#/employees/3/resume?tab=Projects` where The `:?query:` parameter starts and ends with `:`, which means that it is optional. If you want to make it mandatory, you can use the `{?query}` syntax \(everything in between `{}` is considered as being mandatory\). -## webapp/view/employee/Resume.view.xml +### webapp/view/employee/Resume.view.xml ```xml [πŸ“₯ Download step 10](https://ui5.github.io/tutorials/navigation/navigation-step-10.zip) (TS)[πŸ“₯ Download step 10](https://ui5.github.io/tutorials/navigation/navigation-step-10-js.zip) (JS). -### Folder Structure for this Step +#### Folder Structure for this Step ![Folder Structure for this Step](assets/Tutorial_Navigation_and_Routing_Step_10b.png "Folder Structure for this Step") -## webapp/view/employee/Resume.view.xml +### webapp/view/employee/Resume.view.xml ```xml @@ -73,7 +73,7 @@ In the `resume` view we remove the content of the *Hobbies* and *Notes* tabs as Create the file `ResumeHobbies.view.xml` in the `webapp/view/employee` folder. Move the content for the tab that was previously in the `Resume` view to the newly created view. We don’t need a controller for this view as there is no additional logic involved. This view will be lazy-loaded and placed into the content of the *Hobbies* tab with navigation features. -## webapp/view/employee/ResumeNotes.view.xml \(New\) +### webapp/view/employee/ResumeNotes.view.xml \(New\) ```xml @@ -83,7 +83,7 @@ Create the file `ResumeHobbies.view.xml` in the `webapp/view/employee` folder. M Create the file `ResumeNotes.view.xml` in the `webapp/view/employee` folder similar to the *Hobbies* view to transform this tab to a separate view as well. -## `webapp/controller/employee/Resume.controller.ts/.js` +### webapp/controller/employee/Resume.controller.ts/.js ```ts // webapp/controller/employee/Resume.controller.ts @@ -213,7 +213,7 @@ Now we extend the `Resume` controller a little and add additional logic to the p These lines of code make sure that the targets are only loaded when they are needed \(β€œlazy loading”\). But the router does not know the new targets yet, so let’s create them in our routing configuration. -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -290,7 +290,7 @@ We have now implemented lazy loading for the tabs *Hobbies* and *Notes*. These t Try it out yourself: Open the *Network* tab of your browser's developer tools and click on the tabs of your app. In the network traffic you will see that `ResumeHobbies.view.xml` file is only loaded when the *Hobbies* tab is displayed the first time. The same applies for the *Notes* tab. Mission accomplished! -## Conventions +### Conventions - Lazy-load content that is not initially displayed to the user diff --git a/packages/navigation/steps/11/README.md b/packages/navigation/steps/11/README.md index 66d515f2b..bccc38485 100644 --- a/packages/navigation/steps/11/README.md +++ b/packages/navigation/steps/11/README.md @@ -1,32 +1,32 @@ -# Step 11: Assign Multiple Targets +## Step 11: Assign Multiple Targets In this step, we will add a new button to the home page to illustrate the usage of multiple targets for a route. When the button is pressed, a new page opens that contains two parts: a header part at the top and a content part. The content part displays a table of employees that can be sorted and searched. We will use the array notation in the routing configuration to assign multiple targets to a route - a feature that we have not yet introduced. -## Preview +### Preview -### New button Show Employee Overview +#### New button Show Employee Overview ![New button Show Employee Overview](assets/Tutorial_Navigation_and_Routing_Step_11a.png "New button Show Employee Overview") -### Employee Overview with search field +#### Employee Overview with search field ![Employee Overview with search field](assets/Tutorial_Navigation_and_Routing_Step_11b.png "Employee Overview with search field") -### Sort options for the Employee Overview +#### Sort options for the Employee Overview ![Sort options for the Employee Overview](assets/Tutorial_Navigation_and_Routing_Step_11c.png "Sort options for the Employee Overview") You can view this step live: [πŸ”— Live Preview of Step 11](https://ui5.github.io/tutorials/navigation/build/11/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 11](https://ui5.github.io/tutorials/navigation/navigation-step-11.zip) (TS)[πŸ“₯ Download step 11](https://ui5.github.io/tutorials/navigation/navigation-step-11-js.zip) (JS). -### Folder Structure for this Step +#### Folder Structure for this Step ![Folder Structure for this Step](assets/Tutorial_Navigation_and_Routing_Step_11d.png "Folder Structure for this Step") -## webapp/view/Home.view.xml +### webapp/view/Home.view.xml ```xml [πŸ“₯ Do First we add a new button to the `Home` view and add an event handler for the `press` event. -## `webapp/controller/Home.controller.ts/.js` +### webapp/controller/Home.controller.ts/.js ```ts // webapp/controller/Home.controller.ts @@ -94,7 +94,7 @@ sap.ui.define(["ui5/tutorial/navigation/controller/BaseController"], function (B As you know already from the previous steps, we add the `press` event handler `onNavToEmployeeOverview`. It navigates to the route `employeeOverview` which does not exist yet, so let’s create it. -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -197,7 +197,7 @@ The router makes sure that the parent view is loaded in addition to the target v - `EmployeeOverviewContent` -## webapp/view/employee/overview/EmployeeOverview.view.xml \(New\) +### webapp/view/employee/overview/EmployeeOverview.view.xml \(New\) ```xml @@ -256,7 +256,7 @@ The controller does not contain any logic yet, but we will add back navigation f Create the file `EmployeeOverviewTop.view.xml` and place it in the `webapp/view/employee/overview` folder. This view displays a static text for illustration purposes. Change it according to your own requirements. We don’t need a controller for this view -## webapp/view/employee/overview/EmployeeOverviewContent.view.xml \(New\) +### webapp/view/employee/overview/EmployeeOverviewContent.view.xml \(New\) ```xml [πŸ“₯ Download step 12](https://ui5.github.io/tutorials/navigation/navigation-step-12.zip) (TS)[πŸ“₯ Download step 12](https://ui5.github.io/tutorials/navigation/navigation-step-12-js.zip) (JS). -## webapp/manifest.json +### webapp/manifest.json ```json { @@ -72,7 +72,7 @@ You can download the solution for this step here: [πŸ“₯ Do In order to make the search bookmarkable we have to think about how the pattern of the corresponding route should match the bookmark. We decide to allow `/#/employees/overview?search=mySearchQueryString` in order to bookmark a search. Therefore, we simply extend our routing configuration a little. We add the optional `:?query:` parameter to the route `employeeOverview`. We keep in mind that we want to use `search` as the URL parameter for the search term that was entered in the search field. -## `webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js` +### webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js ```ts // webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts diff --git a/packages/navigation/steps/13/README.md b/packages/navigation/steps/13/README.md index b5f49f565..c9b1202dc 100644 --- a/packages/navigation/steps/13/README.md +++ b/packages/navigation/steps/13/README.md @@ -1,20 +1,20 @@ -# Step 13: Make Table Sorting Bookmarkable +## Step 13: Make Table Sorting Bookmarkable In this step, we will create a button at the top of the table which will change the sorting of the table. When the current sorting state of the table is changed, the sorting state will be reflected in the URL. This illustrates how to make the table sorting bookmarkable. -## Preview +### Preview -### Bookmarkable search and sorting +#### Bookmarkable search and sorting ![Bookmarkable search and sorting](assets/Tutorial_Navigation_and_Routing_Step_13.png "Bookmarkable search and sorting") You can view this step live: [πŸ”— Live Preview of Step 13](https://ui5.github.io/tutorials/navigation/build/13/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 13](https://ui5.github.io/tutorials/navigation/navigation-step-13.zip) (TS)[πŸ“₯ Download step 13](https://ui5.github.io/tutorials/navigation/navigation-step-13-js.zip) (JS). -## `webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js` +### webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js ```ts // webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts diff --git a/packages/navigation/steps/14/README.md b/packages/navigation/steps/14/README.md index df73c8429..1949822df 100644 --- a/packages/navigation/steps/14/README.md +++ b/packages/navigation/steps/14/README.md @@ -1,20 +1,20 @@ -# Step 14: Make Dialogs Bookmarkable +## Step 14: Make Dialogs Bookmarkable In this step, we want to allow bookmarking of the dialog box that is opened when the user clicks the *Sort* button. The dialog should automatically open when the URL contains the query parameter `showDialog`. -## Preview +### Preview -### Bookmark for a dialog +#### Bookmark for a dialog ![Bookmark for a dialog](assets/Tutorial_Navigation_and_Routing_Step_14.png "Bookmark for a dialog") You can view this step live: [πŸ”— Live Preview of Step 14](https://ui5.github.io/tutorials/navigation/build/14/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 14](https://ui5.github.io/tutorials/navigation/navigation-step-14.zip) (TS)[πŸ“₯ Download step 14](https://ui5.github.io/tutorials/navigation/navigation-step-14-js.zip) (JS). -## `webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js` +### webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js ```ts // webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts diff --git a/packages/navigation/steps/15/README.md b/packages/navigation/steps/15/README.md index f563ae72b..0dbb90a84 100644 --- a/packages/navigation/steps/15/README.md +++ b/packages/navigation/steps/15/README.md @@ -1,20 +1,20 @@ -# Step 15: Reuse an Existing Route +## Step 15: Reuse an Existing Route The *Employees* table displays employee data. However, the resumes of the employees are not accessible from this view yet. We could create a new route and a new view to visualize the resume again, but we could also simply reuse an existing route to cross-link the resume of a certain employee. In this step, we will add a feature that allows users to directly navigate to the resume of a certain employee. We will reuse the *Resume* page that we have created in an earlier step. This example illustrates that there can be multiple navigation paths that direct to the same page. -## Preview +### Preview -### Navigation to an existing route from a table item +#### Navigation to an existing route from a table item ![Navigation to an existing route from a table item](assets/Tutorial_Navigation_and_Routing_Step_15.png "Navigation to an existing route from a table item") You can view this step live: [πŸ”— Live Preview of Step 15](https://ui5.github.io/tutorials/navigation/build/15/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 15](https://ui5.github.io/tutorials/navigation/navigation-step-15.zip) (TS)[πŸ“₯ Download step 15](https://ui5.github.io/tutorials/navigation/navigation-step-15-js.zip) (JS). -## webapp/view/employee/overview/EmployeeOverviewContent.view.xml +### webapp/view/employee/overview/EmployeeOverviewContent.view.xml ```xml [πŸ“₯ Do In the `EmployeeOverviewContent` view we register an event handler for the `itemPress` event and set the type attribute of the `ColumnListItem` to `Active` so that we can choose an item and trigger the navigation. -## `webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js` +### webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts/.js ```ts // webapp/controller/employee/overview/EmployeeOverviewContent.controller.ts diff --git a/packages/navigation/steps/16/README.md b/packages/navigation/steps/16/README.md index 7e246dbce..9c8a27738 100644 --- a/packages/navigation/steps/16/README.md +++ b/packages/navigation/steps/16/README.md @@ -1,20 +1,20 @@ -# Step 16: Handle Invalid Hashes by Listening to Bypassed Events +## Step 16: Handle Invalid Hashes by Listening to Bypassed Events So far we have created many useful routes in our app. In the very early steps we have also made sure that a *Not Found* page is displayed in case the app was called with an invalid hash. Now, we proceed further and track invalid hashes to be able to detect and correct any invalid links or add new URL patterns that are often requested but not found. Therefore, we simply listen to the bypassed events -## Preview +### Preview -### Console output for invalid hashes when listening to bypassed events +#### Console output for invalid hashes when listening to bypassed events ![Console output for invalid hashes when listening to bypassed events](assets/Tutorial_Navigation_and_Routing_Step_16.png "Console output for invalid hashes when listening to bypassed events") You can view this step live: [πŸ”— Live Preview of Step 16](https://ui5.github.io/tutorials/navigation/build/16/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 16](https://ui5.github.io/tutorials/navigation/navigation-step-16.zip) (TS)[πŸ“₯ Download step 16](https://ui5.github.io/tutorials/navigation/navigation-step-16-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts diff --git a/packages/navigation/steps/17/README.md b/packages/navigation/steps/17/README.md index 5e4b7d68f..f5737b65c 100644 --- a/packages/navigation/steps/17/README.md +++ b/packages/navigation/steps/17/README.md @@ -1,20 +1,20 @@ -# Step 17: Listen to Matched Events of Any Route +## Step 17: Listen to Matched Events of Any Route In the previous step, we have listened for bypassed events to detect possible technical issues with our app. In this step, we want to improve the analysis use case even more by listening to any matched event of the route. We could use this information to measure how the app is used and how frequently the pages are called. Many Web analytic tools track page hits this way. The collected information can be used, for example to improve our app and its usability. -## Preview +### Preview -### Console output for routes matched by listening to routeMatched events +#### Console output for routes matched by listening to routeMatched events ![Console output for routes matched by listening to routeMatched events](assets/Tutorial_Navigation_and_Routing_Step_17.png "Console output for routes matched by listening to routeMatched events") You can view this step live: [πŸ”— Live Preview of Step 17](https://ui5.github.io/tutorials/navigation/build/17/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 17](https://ui5.github.io/tutorials/navigation/navigation-step-17.zip) (TS)[πŸ“₯ Download step 17](https://ui5.github.io/tutorials/navigation/navigation-step-17-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts diff --git a/packages/odatav4/steps/01/README.md b/packages/odatav4/steps/01/README.md index 754d26f77..52f916360 100644 --- a/packages/odatav4/steps/01/README.md +++ b/packages/odatav4/steps/01/README.md @@ -1,10 +1,10 @@ -# Step 1: The Initial App +## Step 1: The Initial App We start by setting up a simple app that loads data from an OData service and displays it in a table. We use a mock server to simulate requests to and responses from the service. The structure and data model created in this step will be used throughout this tutorial to illustrate the OData V4 features in OpenUI5. -## Preview +### Preview **Initial app with a simple table** @@ -12,7 +12,7 @@ The structure and data model created in this step will be used throughout this t *** -## Setup +### Setup The initial code for this step ships with the repository at [packages/odatav4/steps/01/](./). Open it and run: @@ -51,7 +51,7 @@ webapp/ └── App.view.xml ``` -## The Initial App +### The Initial App The downloaded code includes an app that displays a table containing a table of users. For performance reasons, the table only loads 10 users at a time. More data can be retrieved by using the *More* button at the bottom of the page. @@ -59,11 +59,11 @@ During the implementation of the app, we use local mock data so that we can conc The most important files are the following: -### `webapp/index.html` +#### webapp/index.html This file defines the home page of the app. It contains the bootstrap script and tells the runtime where to find our custom resources. It also initializes the mock server that intercepts all requests to the real *TripPin* service and sends back mock responses. -### `webapp/manifest.json` +#### webapp/manifest.json The `manifest.json` descriptor file contains the app configuration. In the `sap.app` section, the OData V4 service is configured as the default service: @@ -80,7 +80,7 @@ The `manifest.json` descriptor file contains the app configuration. In the `sap. ``` -### Mock server \(`webapp/localService/*`\) +#### Mock server \(`webapp/localService/*`\) > πŸ“ > The mock server included in this tutorial is only meant to support the features needed in this tutorial. Currently, there is no "general-purpose mock server" for application development available with OData V4 \(like there is for OData V2\). diff --git a/packages/odatav4/steps/02/README.md b/packages/odatav4/steps/02/README.md index a4e67f44a..a08e33e55 100644 --- a/packages/odatav4/steps/02/README.md +++ b/packages/odatav4/steps/02/README.md @@ -1,8 +1,8 @@ -# Step 2: Data Access and Client-Server Communication +## Step 2: Data Access and Client-Server Communication In this step, we see how the `Table` that is bound to the `People` entity set initially requests its data, and how the data can be refreshed. We use the *Console* tab in the browser developer tools to monitor the communication between the browser and the server. We see the initial request as well as the requests for refreshing the data. -## Preview +### Preview **App with a toolbar that contains a Refresh button** @@ -12,11 +12,11 @@ In this step, we see how the `Table` that is bound to the `People` entity set in You can view this step live: [πŸ”— Live Preview of Step 2](https://ui5.github.io/tutorials/odatav4/build/02/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 2](https://ui5.github.io/tutorials/odatav4/odatav4-step-02.zip) (TS)[πŸ“₯ Download step 2](https://ui5.github.io/tutorials/odatav4/odatav4-step-02-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -138,7 +138,7 @@ We add the event handler `onRefresh` to the controller. In this method, we retri We also add the private method `_getText` to retrieve translatable texts from the resource bundle \(`i18n` model\). -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml ... @@ -170,7 +170,7 @@ We also add the private method `_getText` to retrieve translatable texts from th We add the `headerToolbar` with a single `Button` to the `Table`. The button has a `press` event to which we attach an event handler called `onRefresh`. -## webapp/i18n/i18n.properties +### webapp/i18n/i18n.properties ``` # App Descriptor @@ -193,7 +193,7 @@ refreshSuccessMessage=Data refreshed We add the tooltip and message texts to the `properties` file. -## Under the Hood +### Under the Hood To get more insight into the client-server communication, we open the *Console* tab of the browser developer tools and then reload the app. diff --git a/packages/odatav4/steps/03/README.md b/packages/odatav4/steps/03/README.md index 1b0d246d5..d9d14bd40 100644 --- a/packages/odatav4/steps/03/README.md +++ b/packages/odatav4/steps/03/README.md @@ -1,10 +1,10 @@ -# Step 3: Automatic Data Type Detection +## Step 3: Automatic Data Type Detection In this step, we use the automatic data type detection of the OData V4 model to parse, validate, and format user entries. The service metadata contains type information for the properties of each entity. The OData V4 Model utilizes this information to compute the corresponding OpenUI5 type, including constraints, and sets this type to the OpenUI5 property binding for the entity property. For example, for `` the OpenUI5 type `Int64` is used, which corresponds to the OData type `Edm.Int64`. -## Preview +### Preview **Input does not match the underlying data type** @@ -12,11 +12,11 @@ The OData V4 Model utilizes this information to compute the corresponding OpenUI You can view this step live: [πŸ”— Live Preview of Step 3](https://ui5.github.io/tutorials/odatav4/build/03/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 3](https://ui5.github.io/tutorials/odatav4/odatav4-step-03.zip) (TS)[πŸ“₯ Download step 3](https://ui5.github.io/tutorials/odatav4/odatav4-step-03-js.zip) (JS). -## `webapp/manifest.json` +### webapp/manifest.json ```json { @@ -58,7 +58,7 @@ We now run the app using the `index.html` file and enter values that don't match > πŸ“ > If you explicitly define a type in the binding info of a control, the automatic type detection for that binding will be turned off. For example, if you change the `Input` for `Age` in the view to ` diff --git a/packages/odatav4/steps/04/README.md b/packages/odatav4/steps/04/README.md index fdfd04060..07231df87 100644 --- a/packages/odatav4/steps/04/README.md +++ b/packages/odatav4/steps/04/README.md @@ -1,8 +1,8 @@ -# Step 4: Filtering, Sorting, and Counting +## Step 4: Filtering, Sorting, and Counting In this step, we add features to filter, sort, and count the user data by using the OData V4 model API to apply OData system query options `$filter`, `$orderby`, and `$count`. -## Preview +### Preview **App now has a search field, the entries can be sorted, and you can see how many entities are loaded and how many more are available** @@ -12,11 +12,11 @@ In this step, we add features to filter, sort, and count the user data by using You can view this step live: [πŸ”— Live Preview of Step 4](https://ui5.github.io/tutorials/odatav4/build/04/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 4](https://ui5.github.io/tutorials/odatav4/odatav4-step-04.zip) (TS)[πŸ“₯ Download step 4](https://ui5.github.io/tutorials/odatav4/odatav4-step-04-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -152,7 +152,7 @@ The **`onSort`** event handler requests the data unordered, or in ascending orde We add the `order` property to variable `oJSONData` in `onInit` method. This property stores the current sort order. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 5](https://ui5.github.io/tutorials/odatav4/odatav4-step-05.zip) (TS)[πŸ“₯ Download step 5](https://ui5.github.io/tutorials/odatav4/odatav4-step-05-js.zip) (JS). -## `webapp/manifest.json` +### webapp/manifest.json ```json ... diff --git a/packages/odatav4/steps/06/README.md b/packages/odatav4/steps/06/README.md index fc4104188..af8f75dfe 100644 --- a/packages/odatav4/steps/06/README.md +++ b/packages/odatav4/steps/06/README.md @@ -1,8 +1,8 @@ -# Step 6: Create and Edit +## Step 6: Create and Edit In this step, we will make it possible to create and edit \(update\) user data from the user interface and send the data to the back end. -## Preview +### Preview **Data can now be edited and added.** @@ -10,11 +10,11 @@ In this step, we will make it possible to create and edit \(update\) user data f You can view this step live: [πŸ”— Live Preview of Step 6](https://ui5.github.io/tutorials/odatav4/build/06/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 6](https://ui5.github.io/tutorials/odatav4/odatav4-step-06.zip) (TS)[πŸ“₯ Download step 6](https://ui5.github.io/tutorials/odatav4/odatav4-step-06-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -412,7 +412,7 @@ The `onResetChanges` method handles discarding pending changes. It uses the `res The `onInputChange` event handler manages entries in any of the `Input` fields and triggers updates to the `appView` model as needed. It does an extra check on the `UserName` field to make sure that users cannot be saved without a `UserName`. Otherwise the OData service would return errors because `UserName` is a mandatory field. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 7](https://ui5.github.io/tutorials/odatav4/odatav4-step-07.zip) (TS)[πŸ“₯ Download step 7](https://ui5.github.io/tutorials/odatav4/odatav4-step-07-js.zip) (JS). -## `webapp/App.controller.ts/.js` +### webapp/App.controller.ts/.js ``` ... @@ -88,7 +88,7 @@ You can download the solution for this step here: [πŸ“₯ Do We add the `onDelete` event handler to the controller. In the event handler, we check whether an item is selected in the table and if so, we retrieve the binding context of the selection and call its `delete` method. By doing this, the context is removed from the table on the client side and the deletion is stored as a pending change in the update group of the table's list binding. A call to `_setUIChanges` ensures that the `appView` model reflects the deletion as a pending change and that the *Save* button becomes enabled. The deletion will be submitted with all other changes related to the same update group once the *Save* button is pressed. If the deletion fails on the server side, or the changes are reset via API, the related entity is restored in the table automatically. To distinguish these two situations, the rejected error has `canceled` set to `true` in case of a reset. -## webapp/App.view.xml +### webapp/App.view.xml ``` [πŸ“₯ Download step 8](https://ui5.github.io/tutorials/odatav4/odatav4-step-08.zip) (TS)[πŸ“₯ Download step 8](https://ui5.github.io/tutorials/odatav4/odatav4-step-08-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -76,7 +76,7 @@ The invocation is asynchronous; the `invoke` method therefore returns a `Promise > πŸ“ > Many of the methods in the OData V4 API of OpenUI5 return a `Promise` to manage asynchronous processing -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 9](https://ui5.github.io/tutorials/odatav4/odatav4-step-09.zip) (TS)[πŸ“₯ Download step 9](https://ui5.github.io/tutorials/odatav4/odatav4-step-09-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts @@ -138,7 +138,7 @@ Afterwards the detail area is made visible and is resized. The application also needs to close the detail area if its binding context is deleted. If the deleted context is restored after a failed DELETE request, or undeleted via `Context#resetChanges`, it could be shown in the detail area again, unless the user had selected another row in the meantime. Hence, we call `_setDetailArea` without a context once the context gets deleted, and with the restored context in the error handler of the `Context#delete` API. In `_setDetailArea` we resize the view based on the given context in an appropriate way. -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml [πŸ“₯ Download step 10](https://ui5.github.io/tutorials/odatav4/odatav4-step-10.zip) (TS)[πŸ“₯ Download step 10](https://ui5.github.io/tutorials/odatav4/odatav4-step-10-js.zip) (JS). -## `webapp/controller/App.controller.ts/.js` +### webapp/controller/App.controller.ts/.js ```ts // webapp/controller/App.controller.ts diff --git a/packages/odatav4/steps/11/README.md b/packages/odatav4/steps/11/README.md index ab0602a00..fa4da0542 100644 --- a/packages/odatav4/steps/11/README.md +++ b/packages/odatav4/steps/11/README.md @@ -1,8 +1,8 @@ -# Step 11: Add Table with :n Navigation to Detail Area +## Step 11: Add Table with :n Navigation to Detail Area In this step we add a table with additional information to the detail area. -## Preview +### Preview **A table containing information about friends of the selected user is added** @@ -10,11 +10,11 @@ In this step we add a table with additional information to the detail area. You can view this step live: [πŸ”— Live Preview of Step 11](https://ui5.github.io/tutorials/odatav4/build/11/index-cdn.html). -## Coding +### Coding You can download the solution for this step here: [πŸ“₯ Download step 11](https://ui5.github.io/tutorials/odatav4/odatav4-step-11.zip) (TS)[πŸ“₯ Download step 11](https://ui5.github.io/tutorials/odatav4/odatav4-step-11-js.zip) (JS). -## webapp/view/App.view.xml +### webapp/view/App.view.xml ```xml ``` -### webapp/App.controller.js \(New\) +### webapp/App.controller.ts/.js \(New\) In our controller, we load the `Controller` base class and extend it to define the behavior of our app. We also add the event handler for our button. The `MessageToast` is also loaded as a dependency. When the button is pressed, we now display a "Hello App" message. diff --git a/packages/quickstart/steps/03/README.md b/packages/quickstart/steps/03/README.md index 80a9887de..b3afdb86e 100644 --- a/packages/quickstart/steps/03/README.md +++ b/packages/quickstart/steps/03/README.md @@ -114,7 +114,7 @@ Don't worry too much about the details, we will explain them in the next tutoria ``` -### webapp/App.controller.js +### webapp/App.controller.ts/.js The `onPress` function now also triggers the navigation to the `intro` page. We fetch the `app` control by its ID and instruct it to navigate by calling the `to` method. diff --git a/packages/walkthrough/steps/09/README.md b/packages/walkthrough/steps/09/README.md index c3b46013a..e136dc52f 100644 --- a/packages/walkthrough/steps/09/README.md +++ b/packages/walkthrough/steps/09/README.md @@ -21,9 +21,20 @@ You can access the live preview by clicking on this link: [πŸ”— Live Preview of After this step your project structure will look like the figure below. We will create the `Component.ts/.js` file now and modify the related files in the app. -![Folder Structure for this Step](assets/loio1e237a36972a44ac8522dd1a540ac062_LowRes.png "Folder Structure for this Step") - -*Folder Structure for this Step* +```text +webapp/ +β”œβ”€β”€ Component.ts/.js +β”œβ”€β”€ controller/ +β”‚ └── App.controller.ts/.js +β”œβ”€β”€ i18n/ +β”‚ └── i18n.properties +β”œβ”€β”€ index-cdn.html +β”œβ”€β”€ index.html +β”œβ”€β”€ index.ts/.js +β”œβ”€β”€ manifest.json +└── view/ + └── App.view.xml +``` *** ### Coding diff --git a/packages/walkthrough/steps/09/assets/loio1e237a36972a44ac8522dd1a540ac062_LowRes.png b/packages/walkthrough/steps/09/assets/loio1e237a36972a44ac8522dd1a540ac062_LowRes.png deleted file mode 100644 index 1da9f1413..000000000 Binary files a/packages/walkthrough/steps/09/assets/loio1e237a36972a44ac8522dd1a540ac062_LowRes.png and /dev/null differ diff --git a/packages/walkthrough/steps/26/README.md b/packages/walkthrough/steps/26/README.md index d1cccdfe2..44b04de1c 100644 --- a/packages/walkthrough/steps/26/README.md +++ b/packages/walkthrough/steps/26/README.md @@ -19,9 +19,37 @@ The folder structure of our app project is clearly separating test and productiv The new `localService` folder contains a `metadata.xml` service description file for OData, the `mockserver.js` file that simulates a real service with local data, and the `mockdata` subfolder that contains the local test data \(`Invoices.json`\). -![Folder Structure for this Step](assets/loio7a5e2b02d72d40d388f5e601d7de74df_LowRes.png "Folder Structure for this Step") - -*Folder Structure for this Step* +```text +webapp/ +β”œβ”€β”€ Component.ts/.js +β”œβ”€β”€ controller/ +β”‚ β”œβ”€β”€ App.controller.ts/.js +β”‚ β”œβ”€β”€ HelloPanel.controller.ts/.js +β”‚ └── InvoiceList.controller.ts/.js +β”œβ”€β”€ css/ +β”‚ └── style.css +β”œβ”€β”€ i18n/ +β”‚ └── i18n.properties +β”œβ”€β”€ index-cdn.html +β”œβ”€β”€ index.html +β”œβ”€β”€ localService/ +β”‚ β”œβ”€β”€ metadata.xml +β”‚ β”œβ”€β”€ mockdata/ +β”‚ β”‚ └── Invoices.json +β”‚ └── mockserver.ts/.js +β”œβ”€β”€ manifest.json +β”œβ”€β”€ model/ +β”‚ └── formatter.ts/.js +β”œβ”€β”€ test/ +β”‚ β”œβ”€β”€ initMockServer.ts/.js +β”‚ β”œβ”€β”€ mockServer-cdn.html +β”‚ └── mockServer.html +└── view/ + β”œβ”€β”€ App.view.xml + β”œβ”€β”€ HelloDialog.fragment.xml + β”œβ”€β”€ HelloPanel.view.xml + └── InvoiceList.view.xml +``` You can access the live preview by clicking on this link: [πŸ”— Live Preview of Step 26](https://ui5.github.io/tutorials/walkthrough/build/26/test/mockServer-cdn.html). diff --git a/packages/walkthrough/steps/26/assets/loio7a5e2b02d72d40d388f5e601d7de74df_LowRes.png b/packages/walkthrough/steps/26/assets/loio7a5e2b02d72d40d388f5e601d7de74df_LowRes.png deleted file mode 100644 index 09902422e..000000000 Binary files a/packages/walkthrough/steps/26/assets/loio7a5e2b02d72d40d388f5e601d7de74df_LowRes.png and /dev/null differ diff --git a/packages/walkthrough/steps/27/README.md b/packages/walkthrough/steps/27/README.md index b17701547..829f12cf0 100644 --- a/packages/walkthrough/steps/27/README.md +++ b/packages/walkthrough/steps/27/README.md @@ -19,8 +19,47 @@ Actually, every feature that we added to the app so far, would require a separat We add a new folder `unit` under the `test` folder and a `model` subfolder where we will place our formatter unit test. The folder structure matches the app structure to easily find the corresponding unit tests. -![Folder Structure for this Step](assets/loio1b5613ac3ab94757af2c7823039222a9_LowRes.png "Folder Structure for this Step") -*Folder Structure for this Step* +```text +webapp/ +β”œβ”€β”€ Component.ts/.js +β”œβ”€β”€ controller/ +β”‚ β”œβ”€β”€ App.controller.ts/.js +β”‚ β”œβ”€β”€ HelloPanel.controller.ts/.js +β”‚ └── InvoiceList.controller.ts/.js +β”œβ”€β”€ css/ +β”‚ └── style.css +β”œβ”€β”€ i18n/ +β”‚ └── i18n.properties +β”œβ”€β”€ index-cdn.html +β”œβ”€β”€ index.html +β”œβ”€β”€ localService/ +β”‚ β”œβ”€β”€ metadata.xml +β”‚ β”œβ”€β”€ mockdata/ +β”‚ β”‚ └── Invoices.json +β”‚ └── mockserver.ts/.js +β”œβ”€β”€ manifest.json +β”œβ”€β”€ model/ +β”‚ └── formatter.ts/.js +β”œβ”€β”€ test/ +β”‚ β”œβ”€β”€ Test.cdn.qunit.html +β”‚ β”œβ”€β”€ Test.qunit.html +β”‚ β”œβ”€β”€ initMockServer.ts/.js +β”‚ β”œβ”€β”€ mockServer-cdn.html +β”‚ β”œβ”€β”€ mockServer.html +β”‚ β”œβ”€β”€ testsuite.cdn.qunit.html +β”‚ β”œβ”€β”€ testsuite.cdn.qunit.ts/.js +β”‚ β”œβ”€β”€ testsuite.qunit.html +β”‚ β”œβ”€β”€ testsuite.qunit.ts/.js +β”‚ └── unit/ +β”‚ β”œβ”€β”€ model/ +β”‚ β”‚ └── formatter.ts/.js +β”‚ └── unitTests.qunit.ts/.js +└── view/ + β”œβ”€β”€ App.view.xml + β”œβ”€β”€ HelloDialog.fragment.xml + β”œβ”€β”€ HelloPanel.view.xml + └── InvoiceList.view.xml +``` You can access the live preview by clicking on this link: [πŸ”— Live Preview of Step 27](https://ui5.github.io/tutorials/walkthrough/build/27/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit&test=unit/unitTests). diff --git a/packages/walkthrough/steps/27/assets/loio1b5613ac3ab94757af2c7823039222a9_LowRes.png b/packages/walkthrough/steps/27/assets/loio1b5613ac3ab94757af2c7823039222a9_LowRes.png deleted file mode 100644 index 362bcde5d..000000000 Binary files a/packages/walkthrough/steps/27/assets/loio1b5613ac3ab94757af2c7823039222a9_LowRes.png and /dev/null differ diff --git a/packages/walkthrough/steps/28/README.md b/packages/walkthrough/steps/28/README.md index 5ffc6d974..29666ec9f 100644 --- a/packages/walkthrough/steps/28/README.md +++ b/packages/walkthrough/steps/28/README.md @@ -19,8 +19,52 @@ We haven’t thought about testing our interaction with the app yet, so in this We add a new folder `integration` below the `test` folder, where we put our new test cases. Page objects that help structuring such integration tests are put in the `pages` subfolder that we also create now. -![Folder Structure for this Step](assets/loio27e84d5bd72a485498564b92894869b5_LowRes.png "Folder Structure for this Step") -*Folder Structure for this Step* +```text +webapp/ +β”œβ”€β”€ Component.ts/.js +β”œβ”€β”€ controller/ +β”‚ β”œβ”€β”€ App.controller.ts/.js +β”‚ β”œβ”€β”€ HelloPanel.controller.ts/.js +β”‚ └── InvoiceList.controller.ts/.js +β”œβ”€β”€ css/ +β”‚ └── style.css +β”œβ”€β”€ i18n/ +β”‚ └── i18n.properties +β”œβ”€β”€ index-cdn.html +β”œβ”€β”€ index.html +β”œβ”€β”€ localService/ +β”‚ β”œβ”€β”€ metadata.xml +β”‚ β”œβ”€β”€ mockdata/ +β”‚ β”‚ └── Invoices.json +β”‚ └── mockserver.ts/.js +β”œβ”€β”€ manifest.json +β”œβ”€β”€ model/ +β”‚ └── formatter.ts/.js +β”œβ”€β”€ test/ +β”‚ β”œβ”€β”€ Test.cdn.qunit.html +β”‚ β”œβ”€β”€ Test.qunit.html +β”‚ β”œβ”€β”€ initMockServer.ts/.js +β”‚ β”œβ”€β”€ integration/ +β”‚ β”‚ β”œβ”€β”€ NavigationJourney.ts/.js +β”‚ β”‚ β”œβ”€β”€ opaTests.qunit.ts/.js +β”‚ β”‚ └── pages/ +β”‚ β”‚ └── HelloPanelPage.ts/.js +β”‚ β”œβ”€β”€ mockServer-cdn.html +β”‚ β”œβ”€β”€ mockServer.html +β”‚ β”œβ”€β”€ testsuite.cdn.qunit.html +β”‚ β”œβ”€β”€ testsuite.cdn.qunit.ts/.js +β”‚ β”œβ”€β”€ testsuite.qunit.html +β”‚ β”œβ”€β”€ testsuite.qunit.ts/.js +β”‚ └── unit/ +β”‚ β”œβ”€β”€ model/ +β”‚ β”‚ └── formatter.ts/.js +β”‚ └── unitTests.qunit.ts/.js +└── view/ + β”œβ”€β”€ App.view.xml + β”œβ”€β”€ HelloDialog.fragment.xml + β”œβ”€β”€ HelloPanel.view.xml + └── InvoiceList.view.xml +``` You can access the live preview by clicking on this link: [πŸ”— Live Preview of Step 28](https://ui5.github.io/tutorials/walkthrough/build/28/test/Test.cdn.qunit.html?testsuite=test-resources/ui5/tutorial/walkthrough/testsuite.cdn.qunit&test=integration/opaTests). diff --git a/packages/walkthrough/steps/28/assets/loio27e84d5bd72a485498564b92894869b5_LowRes.png b/packages/walkthrough/steps/28/assets/loio27e84d5bd72a485498564b92894869b5_LowRes.png deleted file mode 100644 index 7260b63cc..000000000 Binary files a/packages/walkthrough/steps/28/assets/loio27e84d5bd72a485498564b92894869b5_LowRes.png and /dev/null differ diff --git a/tools/builder/prepare-gh-pages.js b/tools/builder/prepare-gh-pages.js index 4e850e2c7..9b86f71be 100644 --- a/tools/builder/prepare-gh-pages.js +++ b/tools/builder/prepare-gh-pages.js @@ -139,6 +139,15 @@ function removeTSfromUI5YAML(ui5yaml) { copyFileSync(join(tutorialDir, "steps.json"), join(distTutorialDir, "steps.json")); } + if (existsSync(join(tutorialDir, "assets"))) { + console.log(` πŸŒ… Copying tutorial assets...`); + const tutorialAssets = fg.globSync(["**/*"], { cwd: join(tutorialDir, "assets") }); + tutorialAssets.forEach((asset) => { + mkdirSync(dirname(join(distTutorialDir, "assets", asset)), { recursive: true }); + copyFileSync(join(tutorialDir, "assets", asset), join(distTutorialDir, "assets", asset)); + }); + } + console.log(` πŸ‘‰ Zipping TypeScript sources...`); await Promise.all(steps.map((step) => { return zipDirectory(