Skip to content

Data Binding in Extension

All controls in Mobile Development Kit support data binding. It is recommended that your extension also allows apps to pass values to your extension via ExtensionProperties as binding.

For example:

{
  "Extension": {
    "Module": "MyExtensionFolder",
    "Control": "MyExtensionFileName",
    "Class": "MyExtensionClass",
    "ExtensionProperties": {
      "Title": "{FirstName} {LastName}"
    }
  }
}

Data Binding

When the app that use or consume your extension specified binding via one of the key inside the ExtensionProperties that your extension supports, Mobile Development Kit does not automatically resolve the bindings, the extension itself is responsible to handle the bindings and resolve them at the appropriate time with the appropriate binding context.

You can make use of valueResolver() function which return a valueResolver instance, it has a resolveValue(value, context) function that can be used by your extension to resolve binding value that's passed to the extension from the app. The ValueResolver class spec can be found here.

Note

In regards to ValueResolver.resolveValue parameters:

  1. value parameter: It can be a single object or an array of values. If an array is passed to the function, the result in the promise resolve function will be an array of resolved value with the same order.

  2. context parameter: You can pass the base class context member variable to as the context for resolving the values. IView/IControl/BaseControl base class has a context member variable that you can access e.g. this.context. Or you can create a new Context object with new binding data as the binding context for the value resolver. Context class can be imported from "mdk-core/context/Context"

Example of resolving binding using valueResolver().resolveValue():

  var value = this.definition().data.ExtensionProperties.Value;
  this.valueResolver().resolveValue(value, this.context).then((resolvedValue)=> {
    this._label.text = resolvedValue;
  });

Target Binding

All extensions types support a Target property that allows app that use your extension to bind data to your extension.

{
  "Extension": {
    "Module": "MyExtensionFolder",
    "Control": "MyExtensionFileName",
    "Class": "MyExtensionClass",
    "ExtensionProperties": {
      "Title": "{ProductName}"
    },
    "Target": {
      "EntitySet": "Products",
      "Service": "/MyApp/Services/MyODataService.service"
    }
  }
}

In your extension class, the data retrieved by the Target binding can be accessed in the context.binding property.

The binding property will be an ObservableArray if there's data bound to it. If no Target binding is specified by the app, binding will be undefined.

The following example show you how to consume the Target data binding in your extension and also making use of the value resolver to resolve binding for each individual data entry.

  // Import the Context class so that you can create a new context for each item in the data list
  // Import the isAndroid, iOS to check your current platform
  import { Context } from 'mdk-core/context/Context';
  import { isAndroid, isIOS } from "tns-core-modules/platform";
  // You should call this function in your extension's initialize function and save the returned layout
  private createView() {
    var bindingArray = this.context.binding;

    var layout = null;

    if (isIOS) {
      layout = UIStackView.new();
      //Configuring the paddings around the stack view
      layout.autoresizingMask = UIViewAutoresizing.FlexibleWidth;
      layout.layoutMarginsRelativeArrangement = true;
      let inset = new NSDirectionalEdgeInsets();
      inset.top = 8; inset.leading = 16; inset.bottom = 8; inset.trailing = 16;
      layout.directionalLayoutMargins = inset;
      // Set the layout stacking to be vertical
      layout.axis =  UILayoutConstraintAxis.Vertical;
    }
    else if (isAndroid) {
      layout = new android.widget.LinearLayout(this.androidContext());
      layout.setOrientation(android.widget.LinearLayout.VERTICAL);
      layout.setLayoutParams(new android.view.ViewGroup.LayoutParams(-1,-1));
    }

    if (bindingArray && bindingArray.length > 0) {
      var title = this.definition().data.ExtensionProperties.Title; // Get the properties passed from the app that consume your extension
      var len = bindingArray.length;

      for (var i = 0; i < len; i++){
        var context = new Context(bindingArray.getItem(i)); // Create a new context with data from item(i)
        this.valueResolver().resolveValue(title, context).then((resolvedTitle) => {
          var label = null; //Each entry is represented by a label in this example
          if (isIOS) {
            label = UILabel.new();
            label.text = resolvedTitle;
            layout.addArrangedSubview(label);
          } else if (isAndroid) {
            label = new android.widget.TextView(this.androidContext());
            label.setText(resolvedTitle);
            layout.addView(label);
          }
        }); // Resolve the binding
      }
    }
    return layout;
  }

Last update: August 25, 2020