H5 Scripting

A lot of the readers of this blog are also interested in H5 Scripting. It’s a bit of topic for this blog but we have started to answer some questions. So if you have a specific question on H5 Scripting make sure that you have read the developers guide and then you can ask questions here and if we have time we will try and help out.

97 thoughts on “H5 Scripting

  1. Len Lim

    Hi Gerard… Below is whole code of my script. Not sure where did I do wrong but once I switch to othere transaction, the script is not working correctly anymore.

    var H5SampleRequestTracer3 = (function () {
    function H5SampleRequestTracer3(args) {
    this.scriptName = “H5SampleRequestTracer3”
    this.controller = args.controller;
    this.log = args.log;
    }
    H5SampleRequestTracer3.prototype.logEvent = function (eventName, args) {
    this.log.Info(“Event: ” + eventName + ” Command type: ” + args.commandType + ” Command value: ” + args.commandValue);
    };
    H5SampleRequestTracer3.prototype.attachEvents = function (controller) {
    var _this = this;
    /*controller.Requesting.On(function (e) {
    _this.onRequesting(e);
    });
    controller.Requested.On(function (e) {
    _this.onRequested(e);
    });*/

    this.detachRequesting = controller.Requesting.On(function (e) {
    _this.onRequesting(e);
    });
    this.detachRequested = controller.Requested.On(function (e) {
    _this.onRequested(e);
    });
    controller.RequestCompleted.On(function (e) {
    _this.onRequestCompleted(e);
    });

    };
    H5SampleRequestTracer3.prototype.onRequesting = function (args) {
    this.logEvent(“Requesting”, args);

    if ((args.commandType == “LSTOPT” && args.commandValue == “4”) || (args.commandType == “LSTOPT” && args.commandValue == “2”) || (args.commandType == “KEY” && args.commandValue == “ENTER”))
    {
    if (permit2.trim() == “false”)
    {
    args.cancel = true;
    this.log.Info(“CANCEL!”);
    }
    else
    {
    this.log.Info(“APPROVE!”);
    }
    }
    else
    {
    this.log.Info(“PROCEED : ” + permit);
    }
    };
    H5SampleRequestTracer3.prototype.onRequested = function (args) {
    this.logEvent(“Requested”, args);
    this.detachRequesting();
    this.detachRequested();
    //controller.Requesting.Clear();
    //controller.Requested.Clear();
    };
    H5SampleRequestTracer3.prototype.onRequestCompleted = function (args) {
    this.logEvent(“RequestCompleted”, args);

    };
    H5SampleRequestTracer3.prototype.run = function () {
    var controller = this.controller;
    var key = this.scriptName;
    var cache = InstanceCache;
    // Check the instance cache to see if this script has already attached to this program instance.
    if (cache.ContainsKey(controller, key)) {
    // The script is already attached to this instance.
    return;
    }
    this.log.Info(“Running…”);
    // Add a key to the instance cache to prevent other instances of this script on the same program instance.
    cache.Add(controller, key, true);
    // Attach events.
    this.attachEvents(controller);
    };

    function processItems(result, debug)
    {
    var miRecords = result.MIRecord;

    if(null != miRecords)
    {
    var strOutput = “”;
    for(var i = 0; i < miRecords.length; i++)
    {
    var nameValue = miRecords[i].NameValue;

    for(var j = 0; j < nameValue.length; j++)
    {
    // look for the ORDT or ORTP fields
    if("ORDT" == nameValue[j].Name)
    {
    tmpOrderDate = nameValue[j].Value;
    debug.WriteLine("order date : " + tmpOrderDate);
    }
    else if("ORTP" == nameValue[j].Name)
    {
    tmpOrderType = nameValue[j].Value;
    debug.WriteLine("order type : " + tmpOrderType);
    debug.WriteLine("last digit : " + tmpOrderType.substring(2));
    }
    }
    }
    }
    else
    {
    debug.WriteLine("No records returned");
    }

    if (currentDate.trim() == tmpOrderDate.trim())
    {
    debug.WriteLine("same date");
    permit = true;
    permit2 = "true";
    }
    else
    {
    if (userId == "WHO000643" || userId == "MVXSECOFR")
    {
    debug.WriteLine("good to go");
    permit = true;
    permit2 = "true";
    }
    else
    {
    if (res == "SLSMGR" || res == "MMGR" || res == "MGR")
    {
    var ORTP = tmpOrderType.substring(2);

    if(ORTP == "5")
    {
    debug.WriteLine("good to go");
    permit = true;
    permit2 = "true";
    }
    else
    {
    debug.WriteLine("You are not authorized. Change Not Permitted");
    permit = false;
    permit2 = "false";
    }
    }
    else
    {
    debug.WriteLine("Date not the same. Change Not Permitted");
    permit = false;
    permit2 = "false";
    }
    }
    }

    debug.WriteLine("permit :" + permit);
    debug.WriteLine("permit2 :" + permit2.trim());
    }

    /**
    * Script initialization function.
    */
    var tmpOrderType = "";
    var tmpOrderDate = "";
    var datestring = "";
    var userId = "";
    var company = "";
    var userRole = "";
    var fullDate = "";
    var twoDigitMonth = "";
    var currentDate = "";
    var res = "";
    var permit = false;
    var permit2 = "false";

    H5SampleRequestTracer3.Init = function (args) {
    new H5SampleRequestTracer3(args).run();

    var debug = args.debug;
    var $host = $(".visible-tab-host");

    fullDate = new Date();
    twoDigitMonth = ((fullDate.getMonth().length+1) === 1)? (fullDate.getMonth()+1) : '0' + (fullDate.getMonth()+1);
    currentDate = fullDate.getFullYear() + twoDigitMonth + fullDate.getDate();

    userId = userContext['USID'];
    company = userContext['CONO'];

    var tmpOrderNum = ScriptUtil.FindChild($host, "OAORNO");
    tmpOrderNum = tmpOrderNum.val()
    debug.WriteLine(tmpOrderNum);
    debug.WriteLine(userId);
    debug.WriteLine(company);
    debug.WriteLine("Today : " + fullDate);
    debug.WriteLine("currentDate : " + currentDate);

    res = userId.substring(3,10);
    debug.WriteLine(res);

    $.ajax(
    {
    //url:'/m3api-rest/execute/OIS100MI/GetHead?CONO=110&ORNO=2101449108'
    url:'/m3api-rest/execute/OIS100MI/GetHead?CONO=' + company + '&ORNO=' + tmpOrderNum
    , dataType: 'json', success : function(miResult) { processItems(miResult, debug); }
    }
    ).error(function(e, msg) { debug.WriteLine("error: " + e + " " + msg); });

    };
    return H5SampleRequestTracer3;
    }());

    Reply
    1. gsmarquez

      Hi Len,

      Thank you for posting on the H5 Scripting page.

      But may be you can try this first. I think this line may be causing your script to not work. Try to remove this line on the method H5SampleRequestTracer3.prototype.run().
      This method prevents the script from attaching to the reqesting, etc events on the next reloading of the script.

      // Check the instance cache to see if this script has already attached to this program instance.
      if (cache.ContainsKey(controller, key)) {
      // The script is already attached to this instance.
      return;
      }
      

      If this does not work, can you please provide me the detailed steps on how to replicate your scenario? I will try to run your script.

      Thanks and regards,
      Gerard

      Reply
    1. karinpb Post author

      Theoretically you should be able to use automation mforms:// links in H5 as they support that format and the Automation is taking place in the server but I haven’t tried it myself.

      Reply
  2. Cheggen

    Hi.

    Thanks for a very helpful blog!

    Where do I find the developers guide for H5 scripting?
    I have tried to search for it on Xtreme, but did not find anything.
    Could you provide a download link?

    Christian

    Reply
    1. karinpb Post author

      Hi,
      I’m currently investigating where to find it. In the meanwhile I’m going to send it directly to you but I plan to update this blog with the answer – once I get it from the H5 development team.

      Reply
    2. cgarf

      Hi,
      I tried looking for the H5 developer’s guide as well, and you can search it from Infor Extreme. Just type “H5 Development Guide” in the Search texbox on the upper right, make sure to check Search Documentation, and you will be able to see the file in the result. Although, the file may not be updated because it’s last updated 2014. Maybe we should wait for the H5 Development Team to upload an updated one..

      Reply
  3. Simon Dahlbacka

    The h5 scripting dev guide suggests using $content.Add(…)
    but that (or rather the absolute positioning) does not play nice with the various expanders, I now found that there is also a $content.AddElement that works more like in the “old JScript” days, and plays nicer with the expanders. Any particular reason why the documentation does not suggest using that instead ?

    Reply
    1. karinpb Post author

      Hi,
      The H5 scripting guide as not been updated for a few years. I’ll forward your comment to the development lead for H5. All the examples needs to be updated but I don’t know when an updated version is planned for.

      Reply
  4. Jasper

    Hi Guys,

    Can you please help me with Requesting, Requested and Request Completed in H5 script?
    I had a read of the H5 develop guide but it doesn’t mention those events.
    I am on H5 Client v10.2.2.0
    I’ve got an exception when I call controller.Requested.On(function(args){});
    VM910:13 Uncaught TypeError: Cannot read property ‘On’ of undefined(…)

    This is my code.
    var H5SampleRequestTracer = (function () {
        function H5SampleRequestTracer(args) {
            this.scriptName = “H5SampleRequestTracer”;
            this.controller = args.controller;
    //console.log(args);
        }

        H5SampleRequestTracer.prototype.attachEvents = function (controller) {
            var _this = this;
    console.log(H5SampleRequestTracer.prototype);

    controller.prototype = {};
    controller.Requested.On(function(args){
    console.log(“Requesting triggered”);
    });
    //console.log(controller.prototype);
    console.log(controller.__proto__);

    // console.log(H5SampleRequestTracer.prototype);
        };

    H5SampleRequestTracer.prototype.onRequesting = function(args){
    console.log(“Requesting is triggered”);
    };

    H5SampleRequestTracer.prototype.Requesting = function(args){
    console.log(“Requesting is triggered”);
    };

        H5SampleRequestTracer.prototype.run = function () {
            var controller = this.controller;
            var key = this.scriptName;
            var cache = InstanceCache;
            //console.log(“Running…”);
            // Attach events.
            this.attachEvents(controller);
        };
        /**
         * Script initialization function.
         */
        H5SampleRequestTracer.Init = function (args) {
    //console.log(new H5SampleRequestTracer(args));
            new H5SampleRequestTracer(args).run(args.controller);
        };
        return H5SampleRequestTracer;
    }());

    Thanks for your help.

    Regards,
    Jasper

    Reply
    1. rdespiritu

      Hi Jasper,

      This is not supported in MUA 10.2.2.0. I’d like to clarify if you’re using this version of MUA. Thanks.

      Reah

      Reply
      1. Jasper

        Hi rdespiritu

        Thanks for clarifying.
        Can I please ask if that’s possible to handle Requesting, Requested and Request Completed event?
        If that’s possible, can I please get some sample code?
        Thanks.

        Regards,
        Jasper

  5. cheggen

    Hi.
    I am trying to do something as simple as adding a Label and a Textbox in my H5 script, but i cant figure out how to do it.
    I have dowloaded the H5 dev guide, but it only covers how to add a button, using the “new ButtonElement();”. However, it seems to me that there exists no “TextboxElement()” or “LabelElement()”. Does anyone know where this is documentet, or how you do it?

    I see in the comments above that Simon is mentioning a “h5 scripting dev guide” that suggests using $content.Add(…). My copy of the H5 dev guide says nothing about $content.Add, so is this a different guide that is not on Infor Extreme?

    Thanks in advance for any help!

    Reply
    1. karinpb Post author

      Hi, Cheggen.
      I got your script guide from the development team. You can download the guide on Infor extreme to compare. As for details it’s best if I forward your request.

      Reply
    2. rdespiritu

      Hi Cheggen,

      The content.Add function is used in the guide in crs020_PreviewListHeader.js and other examples. We’re currently updating the dev guide including the examples; we’ll post here when we can make it available. Anyway, here’s a sample script for adding elements.

      var AddElements = (function () {
          function AddElements(scriptArgs) {
              this.controller = scriptArgs.controller;
              this.log = scriptArgs.log;
              this.args = scriptArgs.args;
          }
          AddElements.Init = function (args) {
              new AddElements(args).run();
          };
          AddElements.prototype.run = function () {
              this.addLabel();
              this.addTextBox();
              this.addButton();
          };
          AddElements.prototype.addLabel = function () {
              var labelElement = new LabelElement();
              labelElement.Name = "lblFoo";
              labelElement.Value = "Foo";
              labelElement.Position = new PositionElement();
              labelElement.Position.Top = 1;
              labelElement.Position.Left = 1;
              var contentElement = this.controller.GetContentElement();
              contentElement.AddElement(labelElement);
          };
          AddElements.prototype.addTextBox = function () {
              var textElement = new TextBoxElement();
              textElement.Name = "txtBar";
              textElement.Value = "Bar";
              textElement.Position = new PositionElement();
              textElement.Position.Top = 1;
              textElement.Position.Left = 2;
              textElement.Position.Width = 5;
              var contentElement = this.controller.GetContentElement();
              contentElement.AddElement(textElement);
          };
          AddElements.prototype.addButton = function () {
              var buttonElement = new ButtonElement();
              buttonElement.Name = "btnBaz";
              buttonElement.Value = "Baz";
              buttonElement.Position = new PositionElement();
              buttonElement.Position.Top = 3;
              buttonElement.Position.Left = 1;
              buttonElement.Position.Width = 5;
              var contentElement = this.controller.GetContentElement();
              var button = contentElement.AddElement(buttonElement);
              button.click({}, function () {
                  console.log("Baz was clicked. Text value is " + $("#txtBar").val());
              });
          };
          return AddElements;
      }());
      
      Reply
      1. Jasper

        Hi Guys,

        Can I please ask if it is possible to add a column in listview in H5 client?
        That would be good if I can get some sample code.
        Thanks.

        Regards,
        Jasper

      2. rdespiritu

        Hi Jasper,
        It is possible to add a column by directly manipulating the grid.

        var CustomColumns = (function () {
            function CustomColumns(args) {
                this.controller = args.controller;
                this.element = args.elem;
                this.log = args.log;
            }
            CustomColumns.Init = function (args) {
                new CustomColumns(args).run();
            };
            CustomColumns.prototype.run = function () {
                this.customColumnNum = 8;
                this.addColumn(this.controller.ActiveGrid);
                this.attachEvents(this.controller);
            };
            CustomColumns.prototype.addColumn = function (list) {
                var columnId = "C" + this.customColumnNum;
                this.populateData(list, columnId);
                var columns = list.getColumns();
                var newColumn = {
                    id: columnId,
                    field: columnId,
                    name: "custCol 8",
                    width: 100
                };
                if (columns.length < this.customColumnNum) {
                    columns.push(newColumn);
                }
                list.setColumns(columns);
            };
            CustomColumns.prototype.populateData = function (list, columnId) {
                for (var i = 0; i < list.getData().getLength(); i++) {
                    var newData = {};
                    newData[columnId] = "Dummy Data" + i;
                    newData["id_" + columnId] = "R" + (i + 1) + columnId;
                    $.extend(list.getData().getItem(i), newData);
                }
                var columns = list.getColumns();
                list.setColumns(columns);
            };
            CustomColumns.prototype.attachEvents = function (controller) {
                var _this = this;
                controller.RequestCompleted.On(function (e) {
                    _this.populateData(controller.ActiveGrid, "C" + _this.customColumnNum);
                });
            };
            return CustomColumns;
        }());
        

        We will be creating a wrapper for this in the future.

  6. Amira

    Hello,
    I want to extract an information from selected row in a ListView (sub-file), Have you any idea how to do it?
    Thanks in advance for any help

    Reply
    1. karinpb Post author

      Using the name of the column and a reference to the ListControl (which you can get from PanelState or RenderEngine you can use String value= getColumnValue(string columnName). I’ll try to do a new post with an example when I have some spare time.

      Reply
  7. Mikael

    We would like to know how to build a script in H5 for a M3 list pgm, that adds a button in the header, and when selecting a transaction line in the list, click the button, another M3-program is called with parameters/data from the selected line.
    In Jscript for SO this is rather easy, but we lack good examples for this in H5.
    Thanks in advance!

    Reply
    1. Reah

      Hi Mikael,

      You can use ContentElement.AddElement() to add a button and ScriptUtil.Launch() to open a program. Here’s an example which uses the MFormsAutomation utility to create the automation XML to open MMS002 and set the value of W1OBKV.

      var LaunchProgramWithParams = (function () {
          function LaunchProgramWithParams(args) {
              this.controller = args.controller;
              this.log = args.log;
          }
          /**
          * Script initialization function.
          */
          LaunchProgramWithParams.Init = function (args) {
              new LaunchProgramWithParams(args).run();
          };
          LaunchProgramWithParams.prototype.run = function () {
              var _this = this;
              //Add button
              var buttonElement = new ButtonElement();
              buttonElement.Name = "btnRun";
              buttonElement.Value = "Run";
              buttonElement.Position = new PositionElement();
              buttonElement.Position.Top = 3;
              buttonElement.Position.Left = 1;
              buttonElement.Position.Width = 5;
              var contentElement = this.controller.GetContentElement();
              var button = contentElement.AddElement(buttonElement);
              //Add click event handler to button
              ScriptUtil.AddEventHandler(button, "click", function (event) {
                  _this.onClick();
              });
          };
          LaunchProgramWithParams.prototype.onClick = function () {
              //Get value of first column of first selected row
              var selected = ListControl.ListView.GetValueByColumnIndex(0)[0];
              if (!selected) {
                  this.log.Error("No selected row");
                  return;
              }
              //Build automation
              var auto = new MFormsAutomation();
              auto.addStep(ActionType.Run, "MMS002");
              auto.addStep(ActionType.Key, "ENTER");
              auto.addField("W1OBKV", selected);
              //Launch MForm
              var uri = auto.toEncodedUri();
              ScriptUtil.Launch(uri);
          };
          return LaunchProgramWithParams;
      })();
      
      Reply
  8. Sam

    Hi,
    I was trying to create some customized scripts in H5. I was wondering how can I customize the list by adding a column with editable cells in it? Hope anyone can help. Thanks!

    Reply
    1. Reah

      Hi Sam, here’s an example:

      var EditableCells = (function () {
          function EditableCells(scriptArgs) {
              this.controller = scriptArgs.controller;
              this.log = scriptArgs.log;
          }
          /**
           * Script initialization function.
           */
          EditableCells.Init = function (args) {
              new EditableCells(args).run();
          };
          EditableCells.prototype.run = function () {
              var list = this.controller.GetGrid();
              var customColumnNum = list.getColumns().length + 1;
              this.appendColumn(list, customColumnNum);
              this.populateData(list, customColumnNum);
              this.attachEvents(this.controller, list, customColumnNum);
          };
          EditableCells.prototype.appendColumn = function (list, columnNum) {
              var columnId = "C" + columnNum;
              var editCellFormatter = function (row, cell, value, columnDef, dataContext) {
                  return "<input type=\"text\" class=\"edit-cell\" value=\"" + value + "\"/>";
              };
              var columns = list.getColumns();
              var newColumn = {
                  id: columnId,
                  field: columnId,
                  name: "Custom Column " + columnNum,
                  width: 100,
                  editor: TextCellEditor,
                  editable: true,
                  // cssClass: "",
                  acc: "WE",
                  formatters: [editCellFormatter]
              };
              if (columns.length < columnNum) {
                  columns.push(newColumn);
              }
              list.setColumns(columns);
          };
          EditableCells.prototype.populateData = function (list, columnNum) {
              var columnId = "C" + columnNum;
              for (var i = 0; i < list.getData().getLength(); i++) {
                  var newData = {};
                  newData[columnId] = "Dummy Data" + (i + 1);
                  newData[("acc_C" + columnNum)] = "WE";
                  $.extend(list.getData().getItem(i), newData);
              }
              var columns = list.getColumns();
              list.setColumns(columns);
          };
          EditableCells.prototype.attachEvents = function (controller, list, columnNum) {
              var _this = this;
              this.unsubscribeGetUpdatedCells = controller.RequestCompleted.On(function (e) {
                  //Handle modified cells
                  var grid = e.controller.ActiveGrid;
                  var dirtyRows = grid.getDirtyRows();
                  var colId = "C" + columnNum;
                  for (var _i = 0, dirtyRows_1 = dirtyRows; _i < dirtyRows_1.length; _i++) {
                      var row = dirtyRows_1[_i];
                      _this.log.Info(row.id + ": " + row[colId]);
                      //Unmark as dirty; indicator="dirty"
                      delete grid.getDataItem(_this.getRowIndex(row.id)).indicator;
                  }
              });
              this.unsubscribeDataScroll = controller.RequestCompleted.On(function (e) {
                  //Populate additional data on scroll
                  if (e.commandType === "PAGE" && e.commandValue === "DOWN") {
                      _this.populateData(list, columnNum);
                  }
                  else {
                      _this.detachEvents();
                  }
              });
          };
          EditableCells.prototype.getRowIndex = function (rowId) {
              if (rowId) {
                  return +rowId.replace("R", "") - 1;
              }
              return -1;
          };
          EditableCells.prototype.detachEvents = function () {
              this.unsubscribeGetUpdatedCells();
              this.unsubscribeDataScroll();
          };
          return EditableCells;
      }());
      
      Reply
  9. Marlene

    Hi,
    I was working on migrating a jScript to a typescript and got stuck. I was trying to open a second dialog after a first.

    – Enter pressed
    – Show dialog
    – Yes
    – Do something
    – No
    – Show Dialog 2

    The first Dialog opens with no problem and the doing something works fine too. However, the second Dialog on cancel/no nether shows. Would be nice if you could help find the mistake.

    class TRN {
    private controller: IInstanceController;

    private detachRequesting: Function;
    private detachRequested: Function;

    public static Init(scriptArgs: IScriptArgs): void {
    new TRN(scriptArgs).run();
    }

    public constructor(scriptArgs: IScriptArgs) {
    this.controller = scriptArgs.controller;
    }

    public run(): void {
    // Attach events.
    this.attachEvents(this.controller);
    }

    private attachEvents(controller: IInstanceController): void {
    this.detachRequesting = controller.Requesting.On((e) => {
    this.onRequesting(e);
    });
    this.detachRequested = controller.Requested.On((e) => {
    this.onRequested(e);
    });
    }

    private onRequesting(args: CancelRequestEventArgs): void {
    // Only validate for the enter key (next button).
    if (args.commandType === "KEY" && args.commandValue === "ENTER") {
    var self = this;
    ConfirmDialog.Show({
    header: "Dialog 1???",
    message: "Yes? No?",
    dialogType: "Question",
    closed: (arg) => {
    if (arg.ok) {
    // Do something...
    }
    else if (arg.cancel) {
    ConfirmDialog.Show({
    header: "Sure?",
    message: "Yes? No?",
    dialogType: "Question",
    closed: (arg2) => {
    if (!arg2.ok) {
    args.cancel = true;
    return;
    }
    }
    });
    }
    }
    });
    }
    }
    }

    private secondDialogClosed(arg: IConfirmDialogCloseArgs): void {
    }

    private onRequested(args: RequestEventArgs): void {
    this.detachEvents();
    }

    private detachEvents(): void {
    this.detachRequesting();
    this.detachRequested();
    }

    }


    Thank you for your time! 🙂

    Reply
    1. Reah

      Hi Marlene,

      The ConfirmDialog API currently does not support nested dialogs; only one dialog can exist at a time.
      One thing you can do is set a timeout when opening the second dialog. This makes sure the first dialog is removed before the creation of the second is triggered.

      ConfirmDialog.Show({
          header: "Dialog 1???",
          message: "Yes? No?",
          dialogType: "Question",
          closed: (arg) => {
              if (arg.ok) {
                  // Do something...
              }
              else if (arg.cancel) {
                  setTimeout(function(){
                      ConfirmDialog.Show({
                          header: "Sure?",
                          message: "Yes? No?",
                          dialogType: "Question",
                          closed: (arg2) => {
                              if (!arg2.ok) {
                                  return;
                              }
                          }
                      });
                  }, 300);
              }
          }
      });
      

      Another option is to create your own dialog, instead of using ConfirmDialog. Please note that while this gives you more control, this entails handling forward compatibility on your part. You may have to modify your script should the Infor control library be updated.

      class H5SampleNestedDialogs {
          public static Init(args: IScriptArgs): void {
              new H5SampleNestedDialogs().run();
          }
      
          private run(): void {       
              this.openDialog1();
          }
      
          private openDialog1() {
              //First add the html to the page..
              $("body").append('<div id="dialog1" style="display:none;"><div class="shortMessage" style="margin-top:0;">Yes? No?</div></div>');
      
              //Invoke the dialog on it
              $('#dialog1').inforMessageDialog({
                  title: "Dialog 1???",
                  dialogType: "General",
                  // width: 500,
                  // height: 294,
                  close: function (event, ui) {
                      $(this).remove();
                  },
                  buttons: [{
                      text: "Ok",
                      click: function () {
                          // Do something...
                          $(this).inforDialog("close");
                      }
                  }, {
                      text: "Cancel",
                      click: () => {
                          this.openDialog2();
                          $("#dialog1").inforDialog("close");
                      }, isDefault: true
                  }]
              });
          }
      
          private openDialog2() {        
              $("body").inforMessageDialog({
                  title: "Sure?",
                  shortMessage: "Yes? No?",            
                  detailedMessage: "",
                  dialogType: "Confirmation",
                  showTitleClose: false,
                  close: function (event, ui) {
                      $(this).remove();
                  },
                  buttons: [{
                      text: "Yes",
                      click: function () {
                          // Do something...
                          $(this).inforDialog("close");
                      }
                  }, {
                      text: "No",
                      click: function () {
                          // Do something...
                          $(this).inforDialog("close");
                      }, isDefault: true
                  }]
              });
          }
      } 
      

      Hope this helps.

      Reply
  10. Marlene

    Hi again,
    There used to be the possibility in jScript to set the MaxLenght of an element.

    e.g.

    public function Init(element: Object, args: Object, controller : Object, debug: Object){
    this.controller = controller;
    this.content = controller.RenderEngine.Content;

    var element = ScriptUtil.FindChild(content, "WFORNO");
    element.set_MaxLength(9);
    }

    Is there a way to do this with H5ScriptSDK?

    Thank you for your help! 🙂

    Reply
    1. Reah

      Hi Marlene,

      ScriptUtil.FindChild() returns a JQuery object; you can use the library functions for this.

      let element = ScriptUtil.FindChild(content, "WFORNO");
      element.attr("maxlength","3");
      
      Reply
  11. Georg

    Hi,

    I added a button in OIS300 B panel and want do disable the button until a row is selected. To do so I copied the onSelectedRowsChanged event from the “H5SampleSelectionChanged” example of the H5ScriptSDK.

    Unfortunately, the “onSelectedRowsChanged” event does not trigger on the first selection of a row. Once I have selected a row and I change the selection, the event triggers as expected.

    Due to this behaviour of the event, I am not able to enable the button on the first selection of a row. Is there a way to achieve the described behaviour with a H5 Script?

    Thank you for your help

    Reply
    1. Reah

      Hi Georg,
      This is a bug and an internal ticket has been filed to fix this.
      As a workaround, you can set the selected rows after subscribing to the event so the succeeding selections will work.

      grid.onSelectedRowsChanged.subscribe(handler);
      grid.setSelectedRows([]);
      
      Reply
  12. thibaudatwork

    Tjena Karin,

    In H5 Client script (not H5 Script SDK), how can we get the current Option value? 1-Create, 2-Change, 3-Copy, 4-Delete, 5-Display? I tried controller.Response.ControlData.Bookmark.Opt but it returns 1 for both Create/Change. How to tell these two apart?

    Tack,

    –Thibaud

    Reply
    1. macalat

      I don’t want to presume but if what you’d like is to get the current operation the user did before proceeding with your code, i believe you can check this in the OnRequesting(). You can console.log the commandType and commandValue to get the correct condition. In your case commandType should be LSTOPT.

      Reply
      1. thibaudatwork

        Hi Reah,

        In the JavaScript console, it throws “controller.GetMode is not a function”.

        Grid 11.1.13.0 77
        mne 10.3.1.0.147
        Foundation 10.1.4.4.1
        PPS300/E

        [INFO] [PageController.showContainer] Version: 10.3.1.0.147
        var controller = getActiveController(); // InstanceController {OPTION_LIST_ACC_WE: “listAccWE”, taskName: “PPS300”, SID: “1EA9F2E40FAA9B85079B91B8F78258E3”, IID: “557691F89A07CF6C11E9FC6B3F56615F”, lastFocus: Object…}
        controller.Response.ControlData.Bookmark.Opt // “2”
        controller.GetMode()
        VM136:1 Uncaught TypeError: controller.GetMode is not a function

        These are the available controller.Get* as per code completion, no GetMode, lowercase or uppercase:
        GetCachedSelRows
        GetContent
        GetContentElement
        GetElement
        GetElementValue
        GetGrid
        GetInstanceId
        GetPanelElement
        GetPanelName
        GetProgramName
        GetSortingOrder
        GetValue
        GetView

        I’m developing a script for H5 Client, no SDK. Why does it throw the exception?

        –Thibaud

      2. Reah

        GetMode is not available in your version. It has been included since Version: 10.3.1.0.161. We recommend getting the latest version 10.3.1.207.

  13. Marlene

    Hi 🙂 here again with another issue/question,

    I was trying to set a value in the Requesting.On event.

    I notice it being set for a second to the new value but for the request the original value is used and after the request, the value in the M3 Mask is reset to the old value.

    e.g.

    controller.Requesting.On((e) => { this.onRequesting(e);

    ...

    private onRequesting(args: CancelRequestEventArgs): void {
    this.controller.SetValue("WTEXIN", "012345678");
    }

    Thank you for your help 

    Regards,
    Marlene

    Reply
    1. Reah

      Hi Marlene,
      This is currently not supported. The panel field values have already been collected when the Requesting handlers are executed, so the new value is not used in the request.

      Reply
  14. Georg

    Hi,
    I have a new problem 🙂 when deploying a script in PPS170, the method ListControl.Columns() returns a wrong string array. The array has the correct length (the length of the array equals the number of columns) but the problem is that it contains at any index the string “MVX/” instead of the field name. In further consequence the method ListControl.GetColumnIndexByName() returns always -1. Is this a bug or am I doing something wrong?

    Further, the typing for the method GetColumnIndexByName is missing in the SDK. Therefore, a cast to any of the ListControl object is necessary. Would be great if you could add the typing within the next release 🙂

    Thank you for your help.

    Regards,
    Georg

    Reply
    1. norpe

      This seems like an M3 BE issue. I would check the response XML (using Fiddler for example) and check which column names are returned from the MUA server. If the list column names contains “MVX/” in the response XML the issue is in either M3 BE or the MUA server and needs to be resolved there. Are there any customer modifications for PPS170? If not you might need to create a support ticket.

      Reply
  15. thibaudatwork

    Hi,

    I have two feature requests for ScriptUtil.ApiRequest. I see it invokes $.ajax() for the HTTP request.

    1) Can you return the promise, so that we can use the promise’s functions, such as then()?

    instead of:
    ScriptUtil.ApiRequest = function (…) { $.ajax({ … }) … }
    do this:
    ScriptUtil.ApiRequest = function (…) { return $.ajax({ … }) … }

    2) Can you add support for ES2017 async/await? It is already implemented in Chrome, Firefox, Safari.

    Thank you,

    –Thibaud

    Reply
    1. Reah

      Hi, ScriptUtil.ApiRequest has been deprecated in favor of MIService. I’m afraid we won’t be able to accommodate this request.

      Reply
      1. thibaudatwork

        Reah,

        Do you know in what version MIService was introduced? I scanned the JavaScript in mne 10.3.1.0.147, and the only declaration of MIService I found was at fashionmatrix\odin\odin-m3.js inside the declaration of object M3, but none are in the scope of H5 Scripts. The M3 Core Administration Guide mentions the Mashup Administration Client, and “Toggle the button enable MI service.” I see the Administration Tools menu with Net Extension Manager, but I don’t see the Mashup Administration Client either. And I read Chapter 7 MI Service in the M3 H5 Development Guide Version 10.3.1.0 Published May 2017, but it looks like TypeScript. Is it available for H5 Scripts in JavaScript?

        I appreciate any help.

        Thank you,

        –Thibaud

      2. thibaudatwork

        Reah, I found the Mashup Administration Client at /mashup/admin/ui . It shows MI Service is toggled to enabled, and the BaseURL is correctly set to some https://host:16107/m3api-rest/ , but it shows Has keystore: False. If I fix the keystore, will I finally see M3 or MIService in the Chrome DevTools JavaScript Console? Thanks. –Thibaud

      3. Reah

        Hi, Thibaud. MIService was made available in version 10.3.1.0.195. No need for other settings to enable it. Yes, you can use this with JavaScript. TypeScript compiles to JavaScript, so there should be no difference in functionality. If you look in the Samples directory included in the H5ScriptSDK package, you will find both the TypeScript and the transpiled JavaScript files for the examples in the documentation. I suggest you still check out TypeScript to see its advantages over plain JavaScript.

  16. Matt Ahearn

    FYI: I’ve finished developing the new Infor Education course called M3 13.4 Developing H5 Personalized Script. Check out on Infor Campus. For those of you like I was transitioning from JScript in Smart Office to TypeScript in H5 Client, this course is a good starter to get you going on personalized scripts in the H5 Client.

    Reply
  17. Matt Ahearn

    Another FYI: I’ve also finished developing the new Infor Education course called M3 13.4 Programming in the Web[Mashup] SDK. Check out on Infor Campus. For those of you like I was transitioning from the SDK in Smart Office to Web/Mashup SDK in H5 Client, this course is a good starter to get you going on writing custom applications and Mashup controls in the H5 Client.

    Reply
  18. Matt

    Hi there,

    I ran into a problem while trying to migrate an old JScript to H5: how do I implement radio-group behaviour? There is no RadioElement and for some reason it seems impossible to uncheck a CheckBox from code after it has been added:

    someCheckBoxElement1.Name = "randomCheckBox1";
    someCheckBoxElement2.Name = "randomCheckBox2";
    const checkBox1 = this.contentElement.AddElement(someCheckBoxElement1);
    const checkBox2 = this.contentElement.AddElement(someCheckBoxElement2);
    checkBox1.change({}, () => {
        checkBox2[0].checked = false; // fails
        (document.getElementById("randomCheckBox2") as HTMLInputElement).checked = false; // fails
    });
    $(document).on('change', 'input[id=randomCheckBox1]', function () {
        $('input[id=randomCheckBox2]').prop('checked', false); // fails
        $('input[id=randomCheckBox2]').attr('checked', 'false'); // fails
        $('input[id=randomCheckBox2]').removeAttr('checked'); // fails
        $(this).prop('checked', true); // works however
    });
    
    Reply
    1. Reah

      Hi Matt,
      Here’s an example for adding a radio group:

      var $rbtnGroup = $("<div class='elementContainer' style='position:absolute;top:0px;left:100px;'><div id='testRadio'>" +
                  "<br><input type='radio' id='option1' class='inforRadioButton' name='radioGroup1' value='o1' role='radio' /><label for='option1'>Option 1</label>" +
                  "<br><input type='radio' id='option2' class='inforRadioButton' name='radioGroup1' value='o2' role='radio' /><label for='option2'>Option 2</label>" +
                  "<br><input type='radio' id='option3' class='inforRadioButton' name='radioGroup1' value='o3' role='radio' /><label for='option3'>Option 3</label>" +
                  "</div></div>");
      $rbtnGroup.find(".inforRadioButton").inforRadioButton();
      var contentElement = this.controller.GetContentElement();
      contentElement.Add($rbtnGroup);
      //$("#testRadio input[type='radio']:checked").val();
      

      As for the checkbox, if you try to get the value after setting it with the jQuery function prop(“checked”, false), you will find that it works. However, the change in the value is not reflected in the UI. The following code toggles a checkbox:

      if ($cbox.is(':checked')) {
                  $cbox.prop("checked", false);
                  $cbox.closest("span").removeClass("checked");
      }
       else {
                  $cbox.prop("checked", true);
                  $cbox.closest("span").addClass("checked");
      }
      

      Let me get back to you so I can verify what needs to be done on our side.

      Reply
      1. Matt

        Hi Reah,

        the second solution works perfectly fine and I am going to use that. The first one may be implemented as an h5.script.RadioElement later on? I would like to avoid writing HTML in code and layouting in absolute measurements.

        Greeting

      1. Matt

        Hi Reah,
        thanks for your fast reply. This works but it will trigger the change() eventhandler of #randomCheckBox1. To get radiogroup boxes I had to add a simple flag so toggling the other one back gets skipt when trigger occurs from code otherwise we’ll end up in an infinity loop 😉

  19. Marlene

    Hi again,
    There used to be the possibility of using templates in jScripts
    eg. var uri = new Uri(“mforms://_automation?template=PPS310REPNR1&REPN=” +REPN);

    Can you still use them? If yes were should the template files be placed and how can they be included in the H5 Script?

    Thank you 🙂
    Marlene

    Reply
  20. karinpb Post author

    Hi,
    Template can still be used. They are uploaded in the Data Files tool found under Adminstration in the H5 client. I don’t know the syntax of the URI but check the documentation or if you can find an example on this blog. The template is an .xml file.

    Reply
    1. Marlene

      ah okay so you can still use the old .xml files. I looked through the documentation again but was not able to find a hint on how to include it… the only thing I could find was on how one looks (pg. 55 – Automation XML)

      Reply
    2. Marlene

      Did some more testing and trying. I uploaded the .xml file to the H5 client and tried some versions of calling but none did work 😦
      e.g.
      var uri = “mforms://_automation?template=TestTemplate”;
      ScriptUtil.Launch(uri);

      //like in the Developer Guide
      var uri = “mforms://_automation?data=TestTemplate”;
      ScriptUtil.Launch(uri);

      The only way so far that I got it to work was by calling ?data with the xml code just following it
      e.g.
      mforms://_automation?data=%3c%3fxml+version%3d%221.0%22+encoding%3d%22utf-8%22%3f%3e%3csequence%3e%3cstep+command%3d%22RUN%22+value%3d%22MMS001%22+%2f%3e%3c%2fsequence%3e

      Sadly, this is not what I am looking for 😦

      Reply
      1. karinpb Post author

        Hi,
        I’ve looked at the code and it seems to me like this should work:
        var uri = “mforms://_automation?template=TestTemplate.xml”;
        ScriptUtil.Launch(uri);

        Can you see the request to MUA in a network tool like Fiddler?
        Anything in the Smart Office log?

        I would expect a call to the main servlet with the following parameters. CMDTP=RUN&CMDVAL=TEMPLATE&TEMPLATE_NAME=TestTemplate.xml. I can’t find an example I would have to wait until “norpe” is back and ask him.

        If there is a request to MUA also check the MUA grid log to see if there is any trace of what happens.

      2. Marlene

        Maybe i should have also posted the Error i get…

        in every version i tried so far it gives me the error:
        “The program was terminated due to an error.”

        now i checked in the chorme developer tools – Netlog – the From Data that gets passed is:
        used “mforms://_automation?template=TestTemplate.xml”

        result “CMDTP=RUN&CMDVAL=ate%3DTestTemplate.xml&BMREQ=&SID=97fd73ef5c629d607573b8e870d52706”

        so it cuts off a lot that it would need 😦 wenn passing the information.

        wenn will norpe be back?

      3. karinpb Post author

        He’s back on Monday. But I forgot that this is in the H5 client. It seems to me that the CMDVAL corrupted. It should also forward any values that you pass in. I’ll ask the H5 Developers to have a look.

  21. potatoit

    Hi Karin and Co,

    with Smart Office we were able to retrieve the addresses of grid components like MWS, is there an equivalent method in H5 yet?
    Following on from that question, how is it envisaged that the authentication to MWS would work?

    Cheers,
    Scott

    Reply
    1. karinpb Post author

      Hi Scott,
      With web development this is considerably harder. There is no method to get other URLs and there is no plans to provide it in H5. The reason is simple. You can only access resources on the same server so there is no point in using full URLs, you need to have MWS on the same machine and then a relative path can be used /MWS/xxxx. The reason is that there is no way to authenticate against another grid service using Ajax calls. For good reasons the browser does not allow it. And even if you can call it most services does not allow Cross domain calls (CORS).

      I’m not saying that it is impossible, you can to crazy stuff like showing an overlay where you load a secured web resource on the other server and then if the other server has the same SAML SP and the same IDP in the background it could potentially get authenticated automatically but then you would need to know when to close the overlay and so on and it’s just crazy and not something that you would ever do in production.

      Reply
      1. potatoit

        Hi Karin,

        would there be scope for Infor to add essentially a proxy or helper for the calls to MWS? Even if it was a method that we could submit a SOAP envelope and receive the response where the H5 framework handles the user rights as it does with the API calls?

        Essentially we want to avoid having to handle usernames and passwords when making MWS calls, relying instead that the H5 client is already authenticated.

        Cheers,
        Scott

  22. karinpb Post author

    Hi Scott, If MWS is located on the same grid the user is already authenticated via the grid cookie. There is no plan to create a proxy. With web we don’t have the users credentials. We have been forced to create a proxy for IDM since it has moved to the teckstack grid compared to previous versions but tunneling traffic is adds complexity and server load. In the case of IDM we had no other options but to provide a proxy as infor applications in H5 needed IDM.

    If you have a strong case for MWS proxy I suggest that you officially request a solution for your scenario via support.

    The current option is to install MWS on the same server has H5, it can be another node in the same grid but it needs to be in the same grid so that the user is already authenticated. Where is MWS normally installed?

    User names and passwords cannot be used in scripts. It’s a major security risk. You have to rely on the authentication in the browser.

    Reply
  23. Jonatan Stenbacka

    Hi! Is there any documentation of the properties and methods for each class available somewhere? When doing JScript in Smart Office I usually rely on https://msdn.microsoft.com/en-us/library/mt468159(v=vs.110).aspx to know what I can do with each object, but I can’t find any equivalent documentation for H5 elements. Is there one? Or is there another way to see what kind of properties and object has?

    In my particular case I’m fetching a textfield in a panel by doing “content.GetElement(‘WEITNO’)[0]”, and I now want to know what kind of different properties and methods that are available to me. My end goal is to make the field read-only.

    Reply
    1. Reah

      Hi, Jonatan. The GetElement function returns a jQuery element; you can use the library functions to set its attributes:

      var elem = content.GetElement(‘WEITNO’)[0];
      $(elem).attr("readonly", true);
      

      The H5ScriptSDK documentation is available in Infor Xtreme. You can also check the h5.script.d.ts declaration file in Samples and the project template included in the SDK package, for the available functions and properties.

      For your reference: 
      The PDF file can be found on the Infor Extreme Documentation repository: https://www.inforxtreme.com/esknowbase/root/DLPublic/52175/H5ScriptDevelopersGuide_10.3.1.0.pdf 

      The zip for the H5 Scripting documentation (with samples and templates) are found in a KB Article: https://www.inforxtreme.com/espublic/EN/answerlinkdotnet/SoHo/Solutions/SoHoViewSolution.aspx?SolutionID=1909067

      Reply
      1. Tjalve

        Thanks a lot for the link to the zip-file!
        With TypeScript-template project, this is a must for us developers with C# (and Java)-experience and less JavaScript-experience.
        Unlimited upvote 🙂

      2. Jonatan Stenbacka

        Thanks! I’m unable to find the H5ScriptSDK documentation containing all the available functions and properties for all classes though. Could yo u please tell me where I can find it?

        Will that documentation also contain the available attributes for the jQuery element, like “readonly” and such?

        Apparently setting the “readonly” attribute to true doesn’t work if the field has a browsing (F4) functionality. Because you can still press F4 and pick a value there.

        Thanks a lot for your help!

        Regards,
        Jonatan

      3. Tjalve

        Hi Jonatan,
        If you download the zip-file from the last link in Reah’s answer, you will find most of what you want there.
        The zip-file contains template-projects with samples and documentation. If you use Visual Studio with Typescript, you will get Intellisense-support so that it is a lot easier to see which methods and properties that are available.
        You can even debug with breakpoints, watch etc. in Visual Studio.
        For standard javascript, jQuery etc., you will probably have to look elsewhere (but even here, Visual Studio gives you some hints).

      4. Jonatan Stenbacka

        If I didn’t ask for it in my previous question. Where can I find the available attributes for e.g. a TextBoxElement?

      5. Reah

        The attributes you can set through jQuery are basically the HTML attributes. For more information, you can refer to the jQuery website.
        You can find the properties of H5 elements in the declaration file in the H5ScriptSDK package. If you develop scripts in TypeScript and use this file, the listed properties and functions should be listed as suggestions as you type in your IDE.

  24. Tjalve Morken

    Hi Karin,
    I am migrating a ISO-Jscript to H5-Javascript that is calling a M3 API for each line in a listview.
    In JScript, we could tag the api-request with the current line and this tag was passed on to the response, so that when reading the output from the api-call we could update the correct listivew-line.
    Is that possible to do in H5 Javascript as well?
    In ISO-Jscript, we could do something like this:
    var request = new MIRequest();
    request.Program = api;
    request.Transaction = apiTransaction;
    request.Tag = rowIdx;
    In H5, we are using the ScriptUtil.ApiRequest, but this has only the url as inputparameter and we cannot pass on any other data (like linenumber from the listview)?
    E.g:
    ScriptUtil.ApiRequest(url, CustomColumns.onApiSuccess, CustomColumns.onApiFail);

    Thanks.

    Reply
    1. Reah

      Hi, here’s an example:

      var rowIdx = ListControl.ListView.SelectedItem()[0];
      ScriptUtil.ApiRequest(url, function (result) {
      	_this.onSuccess(result, rowIdx); //Define a success callback function
      }, function (e, msg) {
      	_this.onError(e, msg);
      });
      
      Reply
      1. Tjalve

        Hi Reah,
        I have had a look at your suggestion.
        It can work in some instances, but unfortunately it is not the same as the “Tag”-solution from SmartOffice-JScript and does not solve my issue.

        In my case, I have a JScript that loops over all rows in a listview and calls an api based on the data in the list (and updates a new column).
        This was done in SmartOffice (Jscript) by passing the linenumber in the “Tag”-property of the Request-object and interpret the Tag in the response-object to update the correct row.

        This does not seem to work in your suggested solution, as the rowIdx will be the LAST linenumber in the loop (loop finishes before the response-function is run – because of Javascript Closure).

        I also found that the ScriptUtil.ApiRequest is deprecated – so I tried to switch to using the MIService. I see that the IMIResponse actually DO have a tag-property, but the IMIRequest does not.
        Maybe this is a bug in the H5-implementation, where the tag-property of the IMIRequest is forgotten?

        I actually do not see any way that one can successfully loop over the rows in the listview and know which row to update in the response-function.
        (I could tag the row itself, but I still cannot map to this row in the response-function as I do not have any of the same information there).

        interface IMIRequest extends IMIOptions {
        program?: string;
        transaction?: string;
        record?: any;
        outputFields?: string[];
        }

        interface IMIResponse {
        program?: string;
        transaction?: string;
        item?: any;
        items?: any[];
        metadata: any;
        tag?: any;
        errorField?: string;
        errorType?: MIErrorType;
        error?: any;
        errorMessage?: string;
        errorCode?: string;
        hasError(): boolean;
        }

      2. Reah

        I have filed a ticket to support the tag property in MIService.

        If I understand correctly, the issue you encounter with the rowIdx value is due to the scope of variables in JavaScript. If you are using TypeScript, you can simply make the variables block-scoped by using ‘let’ instead of ‘var’ when you loop through the rows. The following code should log the id for each row and request.

        for (let item of this.controller.GetGrid().getData().getItems()) {
        	MIService.Current.executeRequest(myRequest).then(
        		(response: IMIResponse) => {
        			this.log.Info(item.id);
        		}).catch((response: IMIResponse) => {
        			this.log.Error(response.errorMessage);
        		});
        }
        

        This is transpiled to the following JavaScript code:

        var _loop_1 = function(item) {
        	MIService.Current.executeRequest(myRequest).then(function (response) {
        		_this.log.Info(item.id);
        	}).catch(function (response) {
        		_this.log.Error(response.errorMessage);
        	});
        };
        for (var _i = 0, _a = this.controller.GetGrid().getData().getItems(); _i < _a.length; _i++) {
        	var item = _a[_i];
        	_loop_1(item);
        }
        

        The same can be done for ScriptUtil.ApiRequest.
        Please note that ‘let’ is available in JavaScript but is not yet supported by some browsers.

  25. Anthony Haxby

    Would it be possible to have some guidance regarding the development of custom components for the H5 Client?

    My situation is migrating customizations from SmartOffice to the H5 Client. These are primarily comprised of custom, streamlined interfaces built using Windows Presentation Foundation (Microsoft .NET) that are shown in separate dialogs, typically invoked by choosing a button from the M3 program or the grid context menu.

    From what I can see the H5 Client SDK (Infor M3 H5 Development Guide Version 10.3.1.0) does not include any examples showing a modal window whose content is a custom, interactive HTML template. I’m referring to the implementation of an advanced template, where the content is multiple different HTML input elements with event handlers that update the content of the HTML template when values change. (For instance, a template with a drop-down that, when a value is selected, populates a grid that lets the user select one or more values, and then invoking the MIService multiple times for the user’s selections).

    While the SDK doesn’t provide a sample, this can technically be accomplished by hand-rolling the HTML/event-sinks using JQuery and then showing the content using inforDialog(), but this approach doesn’t seem optimal.

    Is using the H5 Client for these kinds of customizations even recommended? If so, is there any examples that Infor can provide of an implementation? Otherwise, should I be approaching this at a different angle, perhaps using Mongoose or the Infor App Builder?

    Reply
    1. karinpb Post author

      Hi Anthony,
      There is no out of the box answer for your question. Developing for web with HTML5 and jQuery is that much harder than WPF. This all comes down to how much integration you have between the panel and the application. There are a few options I and I think that you have listed them all, except for perhaps using the M3 Mashup SDK to build a stand alone web app that you can deploy to the MUA server. It might be easier to use that and just have the script open a dialog with an IFrame than using JQuery for everything. The M3 Mashup SDK is using AngularJS so you would have templating support (which you don’t have if you just use JavaScript in the H5 client.)

      Mongoose and Infor App Builder are also options that are available for you where Mongoose is the most powerful framework which can include server logic. There is no official recommendation as it “depends” but I would say that writing everything in JavaScript within the H5 is a bit hard since there is no public documentation of the H&L Xi SoHo HTML controls that H5 uses. You would pretty much try and figure things out by reading this blog and looking at the H5 client and the examples it provides. Of course you can ask questions on this blog and via support for specific examples but we don’t have any more examples than the scripting examples already provided. But if you require tight integration with the M3 panel – eg returning data to the panel – this is the only option. If you just need input from the panel to your application you can always pass those as parameters on the URL to another application. If I were you I would spend some time looking at: M3 Mashup SDK, Mongoose, Infor App Builder and then compare those. Smaller things can be done in H5 directly with JavaScript and JQuery.

      Reply
  26. Salman

    Hi Guys,
    I am trying to invoke MI program via H5 scripting but while executing that script I am getting below error.

    Uncaught ReferenceError: MIRequest is not defined

    Below is the simple snippet which I am using.
    const myRequest = new MIRequest();
    myRequest.program = “MNS150MI”;
    myRequest.transaction = “GetUserData”;

    Any help will be highly appreciated.

    Regards, Salman

    Reply
  27. Tjalve

    Using Typescript for H5-scripting is wonderful, but where do you guys keep the ts-files?
    H5 only need the js-files, but I guess everybody wants the ts-files to be the “source” and make sure nobody is modifying the js-files generated from a ts.
    Are you using Version-Control (e.g. GitHub) – and how do you make sure nobody is changing the js-files directly?
    Recommendations, suggestions?

    Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s