Skip to main content
Version: 7.3.1

Reusable Components

Creating and using reusable components are the key element between a successful project and being unable to minimize the effort through the lifetime of project. You can find examples of reusable component even outside of the Software World. Fields like Sales, Animation, Graphics Design or even Film Industry create and re-use some of their actions to ease their workflow.

When You Will Need Components

  • When you are designing ListViewItem and GridViewItem. These views use RecyclerView, therefore it is required to use reusable components.
Using ListView or GridView with UI Editor
  • When you create SliderDrawer. Since it is a global view and acts as a main navigator through the project, creating a component for each section would help to ease out the process.
  • When you have a design pattern like Cards, Profiles or any potentially repeatable UI/UX action, it is strongly recommended to create a component, then to create the same thing over and over again.
tip

If your design requires to have a different color than default palette, make sure to define them on a class rather than creating a separate component.

More info about using UI Editor and Classes can be found below:

Using Style and Classes

How To Create and Use Components

Simply head into the Library tab on the Smartface WYSIWYG editor.

Create And Use Components from UI Editor

  • From the Project Explorer, open the Library pane.
  • Drag a FlexLayout from the toolbox to the Library. This layout represents your first library component.
  • Double click on the FlexLayout that you just moved. This will enable you to insert other components inside your layout.
  • Drag a Button inside of your layout, then save your changes.
  • There you have it! You can use this library component across all of your pages.
  • Now drag flexLayout1 (which is your library component), from the library pane to your page.
  • Don't forget that a library component update will be reflected to all pages using this component. This is the primary advantage of using a library.
  • As an example, change the background color of your button of flexLayout1

Adding Code to the Created Component

Only using UI will not be enough if you want to set things programmatically or want anything dynamic. In that case, you should wrap your code and logic inside of the component file. When you create a component from Smartface UI Editor, Smartface UI Editor will create a file with the component name for you.

This is how the default component page looks like:

scripts/components/FlexLayout1.ts
import FlexLayout1Design from "generated/my-components/FlexLayout1";

export default class FlexLayout1 extends FlexLayout1Design {
pageName?: string | undefined;
constructor(props?: any, pageName?: string) {
// Initalizes super class for this scope
super(props);
this.pageName = pageName;
this.button1.text = "Smartace"; // This was added from the Smartface UI Editor
}
}

You can add functions, properties or anything you wish inside of the component.

Using Style and Classes for Library Components

The library components are no different when it comes to styling. You can use same methods as you would on normal classes.

tip

If you create a class name matching with the component name itself, a new style file will be created, helping with the structure of the theme folder. If not, the changes will be written in common.json


On Library, it will behave like a component blueprint. Therefore, the user properties which are applied directly to the component WILL NOT be applied to the implemented page code. For example, let's change width and height of our component after we have put it in our page:

As it can be seen from the video, the userprops changes are not applied to our implemented code. This will help you to showcase your responsive components which normally doesn't have width/height properties.

info

Same rule goes for classes itself. If you assign a new class to your library component, the changes will not be applied to the other instances.

Create and use Components From Code

caution

This method is not recommended unless you have a strictly specific action to take.

If you want to create a component in runtime and add it to your page, you should emulate the same steps that UI Editor does for you.

You need to create the file like scripts/components/FlexLayout.ts to keep your code clean.

import FlexLayout from "@smartface/native/ui/flexlayout";
import Button from "@smartface/native/ui/button";
import { styleableContainerComponentMixin } from "@smartface/styling-context";
/**
* Since this file wasn't created from Smartface UI Editor,
* you should manually extend the Smartface Component yourself.
*/

class StyleableButton extends styleableComponentMixin(Button) {}

export default class FlexLayout1 extends FlexLayout {
pageName?: string | undefined;
button1: StyleableButton; // You can set this to private if you don't want it to be accssed.
constructor(props?: any, pageName?: string) {
super(props);
this.pageName = pageName;
this.top = 30; // Direct assignment is fine because this is constructor of the component.
this.height = 20;
// Add another view like Button or whatever you want to.
this.button1 = new StyleableButton();
this.addChild(this.button1, "button1", ".sf-button");
}

changeStyle() {
// 3rd parameter is optional and is used to give class name
// 4th parameter is optional and is used to give user properties
this.addChild(myFlexlayout, "myFlexlayout", ".sf-flexlayout", {
top: 60,
height: 10,
flexProps: {
alignSelf: "CENTER",
positionType: "ABSOLUTE",
},
});
}
}

To learn more about what dispatch and other parameters are, refer to the document below:

Using Style and Classes

To learn more about what onLoad or onShow means, refer to the document below:

Page Life-Cycle
tip

If you are going to add another view inside of your component, you should do it in component file itself, not the page file.

Tips & Tricks about Reusable Components

One of the main purpose of creating reusable component is to use it inside of ListView or GridView. Kindly refer to the document below to learn more:

Using ListView or GridView with UI Editor

On Smartface, all UI components inherit the properties one of the following parent components:

View Component

If a component is derived from View, it means the component cannot have child components. E.g. a Button is a component which inherits properties of View, therefore you cannot add child component inside of a Button

ViewGroup Component

If a component is derived from ViewGroup, it means the component is a container component and can receive child component. E.g. a FlexLayout can have child components inside of it.

info

ListViewItem and GridViewItem are components which are derived from ViewGroup, however they are components with a different purpose, therefore they are partially exempt from this practice. Continue reading to learn the best practice on how to use them.

How to Specify Where a Component Belongs

Method 1

Check the hierarchy specified at API Documentation of the component. It is located on the right side of the component page. Example for button:

Method 2

You can also specify which class the UI component inherits by using the power of Typescript.

  • Type the name of the desired component to any scope
  • Let the Typescript Language Features auto-import the class for you
  • Hover the component by pressing down ctrlcmd (ctrl on Windows/Linux, cmd on Mac)
  • The declaration of the component will be shown.
tip

Alternatively, you can directly go into the module in node_modules and directly delve into the d.ts of the component itself.

Using View Based Components as Library Component

When a component is created & reused, the newly reused component will share all of the state the library component has at that time. The parent component will be duplicated and child components will share the same reference as the Library Component.

Therefore, when the developer wants to change something in the component, the following changes will not be applied to the parent of the reused component.

  • User properties of the parent component
  • Classes of the parent component (the changes in the class itself will be applied)

Every change which are made in the child components will be applied to every reused component.

Example Case

Let's say we need to have a Button red colored and rounded. It should also have an extended functionality(e.g prompting a dialog on press)

❌ Don't

Creating a View based Class like this is a bad practice. As explained above, if you need to change about this library class, since the properties will be duplicated instead of being referenced, the other places which use this component will not receive the changes.

✅ Do

Wrap the component with a FlexLayout instead and use [FlexGrow](https://ref.smartface.io/interfaces/flexlayout.IFlexLayout.html#flexGrow to expand your component to your needs. This way, your changes on the Button will be applied seamlessly. You can also apply extra properties to the parent component if it is needed.

💭 If you Only Need to Change Styles

Simply create a class for your button and use them with normal button. For more information about classes, refer to the document below:

Using Style and Classes

Nested Components

You can use library components inside other library components to maximize reusability.

Encapsulation of UI Component

You can encapsulate your UI component to make it more scalable.

With the below example, we have a component called Simple_gridviewItem. We encapsulate it into a class called Simple_gridviewItem. This way, we can reuse the component in other places.

Main purpose of encapsulation is to make your component more scalable and reusable.

Without Encapsulation

If you don't want to encapsulate your component, you can use the below example. But this is not recommended in most cases because it will make your component not reusable.

For example, if you change your Label color based on device, you will have to do it every time the component is used in other places.

Page (Without Encapsulation)

initGridView() {
this.gridViewMain.onItemBind = (GridViewItem: SimpleGridviewItem, index) => {
const { title, subTitle, image } = this.myDataSet[index];

GridViewItem.lblTitle.text = title;
GridViewItem.lblSubtitle.text = subTitle;
if (System.OS === System.OSType.IOS) {
GridViewItem.lblSubtitle.textColor = Color.RED;
} else {
GridViewItem.lblSubtitle.textColor = Color.BLUE;
}
GridViewItem.imgPreview.loadFromFile({file: new File({path: "images://smartface.png"})})
};
}

If you used encapsulation, you don't need to do it every time you use the component in other places.

Component
import Image from "@smartface/native/ui/image";
import Simple_gridviewItemDesign from "generated/my-components/Simple_gridviewItem";

export default class Simple_gridviewItem extends Simple_gridviewItemDesign {
pageName?: string | undefined;
constructor(props?: any, pageName?: string) {
// Initalizes super class for this scope
super(props);
this.pageName = pageName;
}
get gridTitle(): string {
return this.lblTitle.text;
}
set gridTitle(value: string) {
this.lblTitle.text = value;
}
get gridSubTitle(): string {
return this.lblSubtitle.text;
}
set gridSubTitle(value: string) {
this.lblSubtitle.text = value;
this.setSubtitleColor();
}
get gridImage(): string | Image {
return this.imgPreview.image;
}
set gridImage(value: string | Image) {
if (value instanceof Image) {
this.imgPreview.image = value;
} else if (typeof value === "string") {
this.imgPreview.loadFromFile({
file: new File({ path: `images://${value}.png` }),
});
}
}
setSubtitleColor() {
if (System.OS === System.OSType.IOS) {
this.lblSubtitle.textColor = Color.RED;
} else {
this.lblSubtitle.textColor = Color.BLUE;
}
}
}
Page With Encapsulation

initGridView() {
this.gridViewMain.onItemBind = (GridViewItem: SimpleGridviewItem, index) => {
const { title, subTitle, image } = this.myDataSet[index];
GridViewItem.gridTitle = title;
GridViewItem.gridSubTitle = subTitle;
GridViewItem.gridImage = image;
};
}