H5 Scripting

This page has been closed for comments.

We encurage you to use the M3 development at Infor Community for questions, or the H5 SDK git for development of web applications in H5, but please try and avoid posting at multiple locations at the same time.

A lot of the readers of this blog are also interested in H5 Scripting. It’s a bit off topic for this blog, but since we are all in the same team, we have started to answer questions. 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.

M3 H5 Scripting Guide for M3 UI Adapter 10.3.1.0 (always search for the latest version when you are on the support portal).

You can also use the M3 development at Infor Community for questions, or the H5 SDK git for development of web applications in H5, but please try and avoid posting at multiple locations at the same time.

487 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;
    }());
    
    
    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

    2. Jonathan A San Juan

      Hi!
      Is there anyway to catch the when the user closes a tab from a web mashup sdk? I imagine from a H5 js, it’s just a matter of catching button close/F3, but would that also catch the tab close? Can web mashup sdk session also catch the same?

      Thanks!
      Jonathan

      1. Reginald Reyes

        From using script, you can find the class of the selected tab using “$(“.ui-tabs-selected”)” and navigate through the close button, then you must attach your own listener for the close functionality.

        Regards,
        Reggie

      2. HeikoM

        Hi, for people who still need to solve similar problems: In the actual browser versions, there is an object called “MutationObserver” which can be used to monitor changes; a method is automatically called when the observed object changes:

        const config = { childList: true };
        this.observer = new MutationObserver(this.onTablistChanged); // <= the H5 program tabs
        this.observer.observe(this.headerTabsList, config);

        In my case the mashup opened an external tab via bookmark. After closing that tab, the mashup needed to refresh itself

    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.

  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

    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.

    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..

  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 ?

    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.

  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

    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

      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. Jasper

    Hi rdespiritu,

    Sorry, forgot to mention my previous post is still about MUA 10.2.2.0.
    Thanks.

    Regards,
    Jasper

  6. 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!

    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.

    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;
      }());
      
      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.

    1. Ashok kamble

      Hello,
      How to create Hyperlink in data grid for custom column , It means I want to add custom column and want to add data as a hyperlink.
      Thank you.

  7. 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

    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.

  8. 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!

    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;
      })();
      
      1. Ian A.

        Hello,
        I took this and am trying to modify it to run an automation that uses a related option, and then press enter twice and then F3 to be back in the list, but I keep receiving a message that the program was terminated due to an error. I thought instead of using “ActionType.Run” it would be “ActionType.LSTOPT” is this not correct? If i want to use a related option do I need to define the data that the next screen needs? If not, is there a way to select the entire row, instead of data out of individual columns in the row?

        I was also hoping there was a way to have the automation repeat n-times, based on how many rows were selected; is that possible?

      2. Reah

        Hi Ian,
        It should be “ActionType.ListOption”.

        let selectedItems = ListControl.ListView.GetValueByColumnIndex(0);
        let auto = new MFormsAutomation();
        for (let selected of selectedItems) {
        	auto.addStep(ActionType.Run, "MMS002");
        	auto.addStep(ActionType.Key, "ENTER");
        	auto.addField("W1OBKV", selected);
        	auto.addStep(ActionType.ListOption, "2");
        	auto.addStep(ActionType.Key, "F3");
        }
        
      3. Shashank Malali

        Hi Reah,
        I have added the button using your script as above. I have also used mforms automation . Everything works fine. But the button is not visible for very first session of the day when I start.
        I need to refresh the screen of OIS101/H where this script is added. And after the first refresh for all other sessions my button appears. Can you guide me please what may be the issue.
        Actually I have two scripts in OIS101/H one without button and second with Button. Is this causing any issue just because I have two scripts in one program?

  9. 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!

    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;
      }());
      
      1. Jennifer

        Hi! I tried using the TextCellEditor in my script but it is giving me an error “Cannot find name ‘TextCellEditor'” do I need to declare it somewhere first? Thanks!

      2. Reginald Reyes

        Hi Jennifer,
        I think the function “TextCellEditor” is only a part of H5 and not inside the Scripting SDK that’s why you were having errors in your ts file. I think it should work if the transformed js file is uploaded in H5.
        Regards,
        Reggie

      3. Jennifer

        Hi! Has anyone encountered an issue with the editable cell wherein you have to hold the left click so that the cursor will stay inside the cell so that you can type inside the cell? Any ideas on how to fix that issue? Thanks!

  10. 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) =&gt; {
                this.onRequesting(e);
            });
            this.detachRequested = controller.Requested.On((e) =&gt; {
                this.onRequested(e);
            });
        }
    
        private onRequesting(args: CancelRequestEventArgs): void {
            // Only validate for the enter key (next button).
            if (args.commandType === "KEY" &amp;&amp; args.commandValue === "ENTER") {
                    var self = this;
                    ConfirmDialog.Show({
                        header: "Dialog 1???",
                        message: "Yes? No?",
                        dialogType: "Question",
                        closed: (arg) =&gt; {
                            if (arg.ok) {
                                // Do something...
                            }
                            else if (arg.cancel) {
                                ConfirmDialog.Show({
                                    header: "Sure?",
                                    message: "Yes? No?",
                                    dialogType: "Question",
                                    closed: (arg2) =&gt; {
                                        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! 🙂

    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.

  11. 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! 🙂

    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");
      
  12. 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

    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([]);
      
  13. 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

    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.

      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.

  14. 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

    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.

    2. William

      Hi Marlene,

      I would try something like the following in your case:

      // Define a class member called continue, set it to false by default
      if (!this.continue) {
      args.cancel = true;
      this.setFieldValueAndPressEnter(“WTEXIN”, “012345678”);
      }

      // Create a method which will set the value, this.continue to true and then then press the enter
      // key
      private setFieldValueAndPressEnter(field, value) {
      this.controller.SetValue(field, value);
      this.continue = true;
      this.controller.PressKey(‘ENTER’);
      }

  15. 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

    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.

  16. 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

    1. Reah

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

      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.

      4. Ian A.

        Hi!
        Does this mean we will have to update all scripts that use ScriptUtil.ApiRequest? Is it a simple replacement or does the syntax need to change as well? So if I have this line what would it look like using MIService?

        ScriptUtil.ApiRequest(“/execute/CRS610MI/GetBasicData;returncols=YRE2?CUNO= ” + cuno”, response =>{
        var yre2 = response.MIRecord[0].NameValue[0].Value.trim();

  17. 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.

  18. 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.

    1. Daniel Henningsver

      Hi Matt, How do I find this course on the campus? I have tried searching for M3 13.4 but no hits.

      1. Matt Ahearn

        Hi Daniel,

        Infor Education had both new 13.4 courses scheduled in July. It is about time to schedule another round of H5 Scripting and H5 Web SDK training sessions. Watch for on Infor Campus’s calendar soon.

  19. 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
    });
    
    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.

      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

      2. Bhumika Lekurwale

        Hi Reah,

        I tried implementing the first way to add radio buttons in “ConfirmDialog.ShowMessageDialog” but its not working. It just prints Object:object.
        How can we add radio buttons on “ConfirmDialog.ShowMessageDialog” window and then pick up the value of radio option checked by user.

        Regards,
        Bhumika

    2. Reah

      Hi Matt,
      You can manipulate the checkbox this way:

      $('#randomCheckBox1').toggleChecked()
      
      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 😉

  20. 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

  21. 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.

    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)

    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 😦

      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.

  22. 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

    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.

      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

  23. 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.

  24. 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.

    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

      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.

  25. 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.

    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);
      });
      
      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.

    2. Joe Walker

      Hi Tjalve,

      Did you ever find a solution for this? I have the same issue in an H5 Cloud M3 script I am trying to write whereby I highlight a number of rows in a function, call an API for each, but am struggling to match the API responses back up to the rows that call it. Occasionally, they come back in a different sequence. Unfortunately, I don’t really have a unique identifier in the M3 data per row that I can cross check the API response against so was hoping there was a solution whereby the call and the response each have a unique identifier that aligns them.

      Thanks,
      Joe Walker

      1. Tjalve

        Hi Joe!
        My question above was years ago and my memory is not that good 🙂
        But I believe I managed to fix this issue.
        Can’t remember exactly which script I had the issue with, but found a simular script I can share with you (that works).
        If this doesn’t help, feel free to send me your script and I can have a look.
        Here is the code that may put you in the right direction:
        for (let i = 0; i {
        let foundInvoice = false;
        let invoice = “”;
        for (let j = 0; j {
        this.log.Error(“Feil i APS251MI-api: ” + response + ” : ” + response.errorMessage);
        });
        }
        }

        The use of “hasExtensionData” is only to tag lines when they have been updated – to avoid updating the same line(s) again if the user scrolls up and down on the same lines. (This code is to retrieve extra information in a list – and it only needs to be done once per line).
        I don’t think I had any “syncronization-issues” with this piece of code.

        Kind Regards,
        Tjalve.

      2. Tjalve

        Ooops!
        Pasting the code did not work very well…
        Trying again:
        for (let i = 0; i {
        let foundInvoice = false;
        let invoice = “”;
        for (let j = 0; j {
        this.log.Error(“Feil i APS251MI-api: ” + response + ” : ” + response.errorMessage);
        });
        }
        }

      3. Joe Walker

        Thanks for the reply Tjalve. Your reply and code helped and I’ve got it working. Similar to you, in the API response I compare back to check if its a match. The key bit for me was I had to remove duplicate items in the array before calling the API transactions, such that I know an item will only get processed once and then when the API response is returned for that item I can compare it to all selected rows and calculate the new quantity accordingly. That is because from my calling B panel the item can be in there multiple times.

        Thanks again,
        Joe

  26. 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?

    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.

      1. Anthony Haxby

        Thanks for the very detailed response, karin! SmartOffice did offer us a lot of latitude to develop our customizations and it seems that we may have been attempting to fit too much into this approach. We’ll definitely be looking into Infor’s other application/platform options in Mongoose, App Builder and the Mashup SDK to determine if they offer the functionality we need, but it’a also good to know that we can approach the problem by developing custom web-base applications that can be exposed through IFrames and/or browser windows. Thanks again for your assistance.

  27. 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

      1. Salman

        Hi Reah, Thank you so much for your reply. Indeed I upgraded MUA and BE as well and MIService is working now. With previous version even GetMode wasn’t working but its working perfectly OK.
        Once again Thank you for your reply 🙂
        Regards, Salman

  28. 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?

    1. William

      Hi Tjalve,

      We in the M3 Demo Services team are using Git and Gitlab as version control and to store all of our demo solution scripts. On thing that you could to in order to prevent others from updating the transpiled .js-file could be to also minify the script. No one likes to modify minified files… 🙂

  29. Jonatan Stenbacka

    Hi!

    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.

    How do I make a field like that read-only? I.E. so that the user can’t write anything in the field and can’t prompt for a value using F4.

    Thanks in advance!

  30. Reah

    Hi, here’s an example on how to handle key/mouse events. You can find more information on RequestCompleted and other request events in the scripting guide.

        private run(): void {
            this.elem = this.controller.GetContentElement().GetElement("OAORNO");
            this.elem.attr("readonly", true);
            this.attachEvents();
            this.detachReqCompleted = this.controller.RequestCompleted.On(e => {
                this.onRequestCompleted(e);
            });
        }
        private onRequestCompleted(args: RequestEventArgs): void {
            this.attachEvents();
            this.detachReqCompleted();
        }
        private attachEvents(): void {
            this.elem.on("keydown", event => {
                if(event.keyCode === 115) { // F4
                    event.stopPropagation();
                }
            });
            this.elem.off("mousedown"); // Prevent browse from context menu
            this.elem.on("mousedown", event => {            
                event.stopPropagation();
            });
        }
    
  31. Jonatan Stenbacka

    Hi again!

    Is there something like a text area element which you can add to a panel?

    I basically need to display text with several rows. So the normal TextBoxElement is not sufficient, since it seems like you can’t change the amount of rows of the TextBoxElement.

    But I can’t find anything like a text area element. Not in the samples or anything.

    Thanks in advance,
    Jonatan

    1. Reah

      Hi, you can use TextAreaElement and set the length, rows, and columns in Contraint.

      var textArea = new TextAreaElement();
      textArea.Name = "foo";
      textArea.Constraint = {
      	IsNumeric: false, // Not supported
      	IsUpper: false,
      	MaxLength: 5,
      	MaxDecimals: 0, // Not supported
      	MaxRow: 3,
      	MaxColumn: 4
      };
      textArea.Value = "";
      textArea.Position = new PositionElement();
      
  32. Ian A.

    Hi!
    I’ve been trying to get the cursor to automatically go to a desired field during order entry (from the A panel to the next panel, it stays in the field the cursor was in in the A panel. I’ve set the tab order to have it be first, but it doesn’t seem to want to go to that field. Is there a way to create a script to make the cursor default to the field I want?

    1. karinpb Post author

      Hi,
      There are a number of different things that control the focus and the tab order. You can configure the tab order, M3 can return the panel with information on where to put the focus etc. You can try with a script but you can’t do it when the script is initialized because the UI isn’t rendered yet and you even if you dispatch to the UI-thread to do it later, the other logic might also dispatch and change it after your code is run. You can try and use field.setFocusAsync(), but after you receive the response with the panel that comes after the B-panel. I don’t know all the details so I’ll ask norpe to see if he can give you a more detailed (and correct) answer.

  33. Jonatan Stenbacka

    Hi!

    There’s some documentation on how to extract data from selected rows in a list, but I can’t find any info anywhere on how to just extract data from lets say all rows (without them being selected).

    I guess this is possible somehow?

    Thanks,
    Jonatan

    1. Jonatan Stenbacka

      Hi!

      Is there any plans on implementing this functionality if it isn’t there yet?

      This is the most common request from my customers that needs H5 scripts, and right now I have to tell them that it isn’t possible in H5 yet.

    2. Reah

      Hi Jonatan,

      The following snippet iterates through the currently loaded rows in the grid:

              const grid = this.controller.GetGrid();
              const data = grid.getData().getItems();
              let x = 1;
      
              for (let row of data) {
                  let rowValue = "";
                  for (let keys in row) {
                      //row value has indexes that start with C followed by the column number
                      if (keys.indexOf("C") === 0 && keys.length < 4) {
                          rowValue += row[keys] + ","; 
                      }
                  }
                  this.log.Info("Row #" + x + ": " + rowValue);
                  x++;
              }   
      
  34. Georg Schmidhammer

    Hi,

    I am migrating some older ISO scripts to H5 scripts and I am struggling with the datepicker element. Is it possible to add a datepicker with a H5 script?

    Thanks,
    Georg

    1. Reah

      Hi Georg,
      You can use the inforDateField from the Infor control library with a TextElement.

      const textElement = new TextBoxElement();
      textElement.Name = "dateFoo";
      textElement.Position = new PositionElement();
      textElement.Position.Top = 1;
      textElement.Position.Left = 2;
      textElement.Position.Width = 20;
      textElement.DateFormat = "YYMMDD";
      
      const contentElement = this.controller.GetContentElement();
      const $dateElem = contentElement.AddElement(textElement);
      
      $dateElem.inforDateField({
      	hasInitialValue: true,
      	openOnEnter: false,
      	beforeShow: function() {
      	    if ($(this).val() == "") {
      	        $(this).datepicker("setDate", new Date());
      	    }
      	}, 
      }); 
      

      I have filed a ticket to create an API function for this.

      1. Jonathan SJ

        Hi Reah,

        Is there a way to add a datepicker to dialog box?
        I use the below dialgoContent to create the dialog html, but I can’t figure out how to include the above javascript into this sort of implementation:

        var dialogContent = $(“”);
        dialogButtons = [ //Dialog box button Ok and Cancel
        { //”Ok” button to call submit for approval
        text: “Ok”,
        isDefault: true,
        width: 80,
        click: function () {

        }
        }
        },
        { //Close dialog box
        text: “Cancel”,
        width: 80,
        click: function () {
        $(this).inforDialog(“close”);
        }
        }
        ];
        var dialogOptions = {
        title: “Selection”,
        dialogType: “General”,
        modal: true,
        width: 400,
        minHeight: 200,
        icon: “info”,
        closeOnEscape: true,
        close: function () {
        dialogContent.remove();
        },
        buttons: dialogButtons
        };
        dialogContent.inforMessageDialog(dialogOptions);

        Regards,
        Jonathan

      2. Reah

        Hi Jonathan,
        You can add the text field manually in the custom dialog. Just make sure to add the css class ‘inforDateField’ to the element.

        const dialogContent = $(`
        <div>
        	<label class='inforLabel noColon'>Custom dialog content</label>
        	<br/ ><br/ ><br/ >
        	<input type=text id='dateFoo' class='inforDateField' />
        </div>`);
        
        const dialogOptions = {
        	title: "Date picker Test",
        	dialogType: "General",
        	modal: true,
        	minHeight: 200,
        	closeOnEscape: true,
        	close: function () {
        		dialogContent.remove();
        	},
        	open: function() {
        		$("#dateFoo").inforDateField({ }); 
        	}
        };
        dialogContent.inforMessageDialog(dialogOptions);
        
      3. Jonatan Stenbacka

        Hi Reah!

        When I just copy-paste your example, the text in my date picker is displayed as MM/DD/YYYY, even though the date format is set to YYMMDD. So it looks likes this DateFormat property on the text element doesn’t actually change the date format.

        This becomes looks very strange to the user if the rest of the dates in a panel is displayed in YYMMDD. Is it possible to change date format somehow? Preferably I would like to be able to set the date format however I’d like, to match the date format of the M3 user.

        Best regards,
        Jonatan

      4. Jonatan Stenbacka

        Hi! See my question above. I would really need a solution to this. Many of our customers need custom date pickers in H5.

      5. Johanna

        Hi Reah,

        I wonder if it is possible to change date format? I can’t change date format by using textElement.DateFormat = “DDMMYY” or textElement.DateFormat = “DMY”. Do you know how I can get it to work?

        Thanks in advance!

        /Johanna

      6. Reggie

        Hi Jonatan and Johanna,
        The fields date format is completely tied up to the business engines format, I think the date format is limited for “YMD”, “DMY”, “MDY”, “YWD” respectively. You may change the date format of the field if you hijack the elements’ attribute, but it doesn’t change the value coming from BE, you will always need to re-format the values coming from BE to your desired format. but it will not change the true date format in the backround.
        Regards,
        Reggie

      7. Johanna Olsen

        Hi Reggie,

        Thank you for your response regarding date format. I could set the date format though when doing that I found some problem with the calendar. If I use and set “dateFormat”, the calendar will open with January. If I don’t set any “dateFormat” the calendar will open with todays date defaulted (which I wan’t). Do you have any idea of how I can get the calendar to open with todays date and also sets the the dateFormat?

        $dateElem.inforDateField({
        hasInitialValue: true,
        openOnEnter: false,
        startDate: new Date(),
        dateFormat: ‘yymmdd’,
        beforeShow: function () {
        if ($(this).val() == “”) {
        $(this).datepicker(“setDate”, new Date());
        }
        },
        })

      8. Reggie

        Hi Johanna,
        Try to simplify first the inforDateField initialization.
        ex.
        $(“#dateInput1”).inforDateField({
        dateFormat: “yyMMdd”
        });

        I used this and it opens up the date today with the format “200706”.

        Regards,
        Reggie

      9. Johanna Olsen

        Hi again Reggie,

        Thank you for your answer, though there still are problems. What you say works at first but as soon as I select a date in the calender the selcted date displayed in the date field is wrong. I selected 6th of July and the display date is then “200006”. Then when opening the calendar again it is back to January… Can you see if you get the same error when you select a date in the date picker after you have set the date format?

  35. priyanthahet

    Hi

    How call h5 personalization script (javascript) using web mashup. Web mashup was developed using smart office mashup tool and export as web mashup.

    Tx

    1. Reggie

      Hi priyanthahet,
      You can only access the personalization script tool inside the regular form and not in web mashup. Any customizations should be done inside the regular forms.
      Regards,
      Reggie

  36. Marcus

    Hi,
    Is it possible to ge any example on how to use the “ComboBoxElement” ? How to add “options” to the list and also on how to get the selected values.

    I have made some tests and can’t get it to work. I can add the box on the screen but I can’t manage to add any “options” to the list or open the dropdown.

    Thanks in advance!

  37. Jonathan SJ

    Hi,

    I have a requirement to automate ‘select all rows’ in a B panel and hit an existing related option. There is the code this.controller.ListOption(buttonInfo.option) to call the related option. But I can’t find a working equivalent to do the same as a ‘ctrl-a’ key press to select all rows.

    I’ve tried :
    $(“.slick-row”).addClass(“selected”);

    But it only highlights all rows. They are not added to the selected list. So the related option thinks you didn’t select a row.

    Do you have any suggestions here?

    Thanks,
    Jonathan

    1. Anthony Haxby

      The underlying grid is an instance of a SlickGrid that exposes a method for setting the row selection.

      In your TypeScript you’ll need a reference to the IInstanceController (from your Init method the IScriptArgs parameter exposes this through its controller property). From there the following snippet will set the selected rows:

      let controller = … // Assume this references your IInstanceController
      this.controller.GetGrid().setSelectedRows([1, 3, 5, 7]); // setSelectedRows expects an array of the row indeces to be selected

  38. Jonatan

    I can’t seem to post new comments in this forum any more. I just get “sorry, this comment could not be posted”. Do you know why this is?

    I’ve tried to post a question in this forum multiple times, but I just get “this post already exists”, or something like that. However, I can’t find the post here on the forum, so it apparently hasn’t been posted.

    Best regards,
    Jonatan

    1. karinpb Post author

      Hi,
      I haven’t seen any issues on my end but I’m going to have a closer look around. This comment came through 😁

      1. Jonatan

        Thanks! Today I at least don’t get any “this comment could not be posted” message, but instead I get the “Duplicate comment detected; it looks as though you’ve already said that!” (I’ve copied my question into a text document so that I could try to re-post it when it didn’t work).

        But I can’t find my question anywhere in this thread. Is it stuck somewhere?

  39. Amy

    I’m looking for an H5 script that would serve as an input mask for phone numbers in H5 CRS610 / customer telephone number. Is this something that could be achieved through a script?

  40. Jonatan

    I can’t seem to change the value of a LabelElement. Whatever method or property I try to change, the text that is shown in the label remains the same.

    I have tried both changing the text using the JQuery method:
    this.label.val(“testing”);
    … and the LabelElement method:
    this.label.Value = “testing”;

    But none of them changes the actual text in the label.

    1. Reah

      Hi Jonatan,
      You can use the jQuery method .text().

      var $label = this.contentElement.AddElement(labelElement);
      $label.text('testing');
      
  41. Joe Walker

    Hi,

    I have just begin the process of converting my Smart Office scripts to H5 client and have ran into two problems I am stuck on. I wonder if anyone has an answer for them please:

    1. On buttons you add to a panel, is there the ability to add a tooltip such that when you hover over the button you get a longer amount of text than just shows on the button itself? I often use this for a description of what the button does. This was done with button.ToolTip in Smart Office but there does not seem to be an H5 equivalent from what I can see. It is not mentioned in the developers guide and visual studio does not seem to suggest one.

    2. For scripts in detail panels, whereby an error message dialog is shown and then the user is left in the panel and focus is placed on a particular field (the one in error), I have been trying to use ScriptUtil.FindChild(host, “MMECVE”).focus(). However, this only works when the focus is on the panel, if you show a dialog box instead the focus is on that and therefore it does not work. Infor support suggested setting the focus on closing the dialog box and that might work – which was not something you had to do in smart office. Has anyone coded this before or have an alternative solution?

    Thanks,
    Joe

    1. Reah

      Hi Joe,

      1. Adding tooltips is currently not possible using the API, but you can do this directly with the Infor control library that H5 uses. Please note, however, that this entails handling forward compatibility on your part as this not part of the API.

      2. You can set the focus of the element on close of the message dialog by specifying it in the dialog options.

              const buttonElement = new ButtonElement();
              buttonElement.Name = "testButton";
              buttonElement.Value = "Show Dialog";
              buttonElement.Position = new PositionElement();
              buttonElement.Position.Top = 4;
              buttonElement.Position.Left = 11;
              buttonElement.Position.Width = 10;
      
              const $button = this.contentElement.AddElement(buttonElement);
              $button.click({}, () => {
                  ConfirmDialog.ShowMessageDialog({
                      dialogType: "Information",
                      header: "Test",
                      message: "Test message",
                      closed: function (arg) {
                          setTimeout(() => {
                              $("#testTextBox").focus();
                          }, 0);
                      }
                  });
              });
              $button.attr("title", "This is a test button.").inforToolTip();
      
  42. Joe Walker

    Hi Reah,

    I have an additional question if you don’t mind please. I am using the standard supplied script H5SampleImageFromList to show an image in MMS001 of the item. However, when I try and run it I get the following error in the console log:

    SCRIPT438: Object doesn’t support property or method ‘GetContentBody’

    I get this in both IE and Chrome but I am on H5 client 10.3.1 which the documentation states is the version where this should be available. So I don’t think its a case of my H5 client version being behind which the odd issue like this has been in the past.

    Any ideas please?

    Thanks in advance,
    Joe

  43. Jonatan Stenbacka

    Hi! Is there a way to – and is it necessary – to clear script cache in H5?

    I’ve had several situations where some old script is cached somewhere and loaded, even though I can see that the new script is imported in “Administrator tools” -> “Data files”.

    At those occasion I’ve just logged out and then tried a few days later, and the problem has fixed itself. But I guess I missed something somewhere.

    Thanks,
    Jonatan

    1. karinpb Post author

      The file should be updated when it’s uploaded. The H5 version that I tested added generated query parameter to the script, eg https://server.infor.com/mne/scripts/Demo.js?_=1527829053795

      It is possible that the version you are using does not have a cache busting parameter like that which means that it is probably stored in the browser (clear browser cache) but it is also possible that it is stored in the web server that is sending the files.

      I would try and download the script directly – with an extra parameter (could be anything, ?hepp=hej). Just to verify that the upload works OK.

      If your version does not have a cache busting parameter then see if you can upgrade to the latest fix pack. Generally you would need to login and out again to get the updated scripts (if you have already loaded it during the session).

      If you still have this issue after that please report it to support.

  44. sid

    Hi
    I have my script in ois101 and I need to check in the script if the user browsed thru Ois100 or ois300 to Ois101. Is there a controller method to check the calling program in OIS101?
    Thanks

    1. karinpb Post author

      Hi sid,
      The application call stack is not available to scripts. You would have to have scripts running on all locations that a user can browse from and store it in the global cache to do this manually. E.g. save a “OIS101Source”, but it would be tedious and I can’t recommend it.

      You can submit an enhancement request to support to request that we provide an API for the call stack information.

  45. BULITHH

    HI,
    May I know how to add Combobox to a panel using H5 script. I have tired couple of ways and any of that did now work ,

    Thanks
    BULITH

    1. Reah

      Hi, here’s an example in TypeScript:

             const items = [
                  { key: '1', value: 'One', selected: true },
                  { key: '2', value: 'Two', selected: false  },
                  { key: '3', value: 'Three', selected: false  },
                  { key: '4', value: 'Four', selected: false  },
                  { key: '5', value: 'Five', selected: false  },
              ];
      
              const comboBox = new ComboBoxElement();
              comboBox.Name = "testComboBox";
              comboBox.Position = new PositionElement();
              comboBox.Position.Top = 4;
              comboBox.Position.Left = 18;
              comboBox.Position.Width = 8;        
      
              for(let item of items) {
                  const cboxItem = new ComboBoxItemElement();
                  cboxItem.Value = item.key;
                  cboxItem.Text = item.value;
                  if(item.selected) {
                      cboxItem.IsSelected = true;
                  }
                  comboBox.Items.push(cboxItem);
              }
              
              this.contentElement.AddElement(comboBox);
      
  46. m3talks

    Hi
    Using H5 script I have added text box to a MMS001 B panel . However when user press the enter button, contents in the text get cleared up(not the refresh) . So how to avoid that ?.

    Thanks
    Pra

    1. karinpb Post author

      Hi, The M3 UI is driven from the M3 server. The M3 server has a view definition that defines the UI and since you have pressed enter the panel has been submitted and the server will give you the next panel, in your case it is the same panel with a fresh set of rows as you have positioned yourself in the list. Your script will run again. You can keep the script running for a longer time and add the textbox back (with content) as long as the reply from the server says that you are still on MMS001B, if you are on another panel after the request has completed then you must disconnect the script. There should be some examples of the events and how to subscribe to them on the blog. Use a tool like Fiddler to see the communication between Smart Office and the M3UIAdapter for a deeper understanding.
      Basically:
      – before the request is made save the text box value in a variable in the script, but don’t disconnect
      – on the response. Check the panel in the reply. Anything else than MMS001B – disconnect. If you are still on MMS001B – Add the text box and if you have a value add the text box. There might be scenarios like after a page down where the textbox is still there so if you have it a name you can search for it on the panel to see if it remains in the visual tree.

      Something like that would do the trick – but I don’t have an example for it.

  47. priyantha

    Hi ,

    I am developing a H5 script . I have introduce textbox. when user press enter button , it gives waning message.
    I have two issue.
    1. How can I retrieve M3 Error or waning message.
    2. Textbox is clear when user press enter and show waning message.

    please help me to resolve above issues .

    Thank you
    Priyantha

    1. Reah

      Hi Priyantha,
      There is currently no API function to easily retrieve this. One workaround is to parse the server response. You might want to do this inside your RequestCompleted instance event handler – there are examples in the H5ScriptSDK package if you need more information on how to do this.

      var xml = $(controller.Response.RawContent);
      var ctrlData = xml.find("ControlData");
      var msg = ctrlData.find("Msg").text();
      
  48. m3talks

    Hi
    When Button is clicked on a panel i want to show to popup form and user should be able to feed some values to that form .(Simple popup with 3 text boxses and ok cancel button) .Based on form inputs i want to do some actions in panel .

    Can anyone share a code to add popup for a panel?

    I have tired with jquery popup and it didn’t work

    THanks
    Pra

    1. Reah

      Hi Pra,
      Here’s a simple example:

      // Create the dialog content
      var dialogContent = $(`
      <div>
      	<label class='inforLabel noColon'>Input</label>
      	<input type="text" id="foo" class="inforTextbox" />
      </div>`);
      var dialogButtons = [
      	{
      		text: "OK",
      		isDefault: true,
      		width: 80,
      		click: function () {
      			// Retrieve user input
      			args.log.Info("User entered: " + $("#foo").val());
      			$(this).inforDialog("close");
      		}
      	},
      	{
      		text: "Cancel",
      		width: 80,
      		click: function () {
      			$(this).inforDialog("close");
      		}
      	}
      ];
      var dialogOptions = {
      	title: "A custom dialog title",
      	dialogType: "General",
      	modal: true,
      	width: 300,
      	minHeight: 300,
      	icon: "info",
      	closeOnEscape: true,
      	close: function () {
      		dialogContent.remove();
      	},
      	buttons: dialogButtons
      };
      // Show the dialog
      dialogContent.inforMessageDialog(dialogOptions);
      
      1. Jonatan Stenbacka

        Sorry, but how do you insert the code into your question so you get the line numbers and everything?

    1. Ashok kamble

      Hello Frode,
      I have aso exact same reqirement, have you found solution for that?
      Thank you.

  49. Kat

    I have a requirement to change the value of one of the field ALQT in sub-file in MMS120 screen using H5 Script. Please advice me how can I change the value of a field in subfile?.

    1. Reah

      Hi Kat,
      Here is an example:

      const grid = this.controller.GetGrid();
      const items = grid.getData().getItems();
      const colIndex = ListControl.GetColumnIndexByName("ALQT") + 1;
      for(const item of items) {
      	item[`C${colIndex}`] = "foo";
      }
      grid.setColumns(grid.getColumns());
      

      If the field is not editable, this can also be achieved without a script using conditional styles as a personalization in the panel.

  50. Ken Eric Gilja

    Hi,

    In the Script sample H5SampleCustomDialog.js the comment text is referring to open a webSDK application from the script in a dialog window, as far as I can understand(?).

    We have a webSDK on the following path:
    Path: /mne/apps/mashupintegration

    But im struggling how to set the dialogContent to the webSDK we deployed.

    Would it be possible to get an example how to set the dialogContent to a webSDK?

    // Create the dialog content
    // Change the dialog content to the webSDK. Save the local data to the cache and use on open and close.
    var dialogContent = $(“Custom dialog content”);

    Thank you.

    Regards
    Ken Eric

    1. karinpb Post author

      Hi Ken,
      I don’t have such an example but it should be a matter of creating an IFrame and setting the URL. But I think there could be issues with the size of the dialog as the SoHo dialog by default tries and adjust to content.

    2. Reah

      Hi Ken,
      You can create the iframe this way:

      var dialogContent = $(`<div><iframe width="100%" height="100%" src='/mne/apps/mashupintegration/'></iframe></div>`);
      
  51. Jonatan Stenbacka

    Hi!

    controller.PressKey(“ENTER”) does for some reason not do anything in my code. Below is my code. On row 80 in the checkDate() method I do “this.controller.PressKey(this.lastCommand);”, where I’ve checked that this.lastCommand is indeed ENTER, but nothing happens in the environment when this line of code is executed.

    class APS100_DateControl {
    private args;
    private controller;
    private content;
    private log;

    private detachRequested: Function;
    private detachRequesting: Function;

    private lastCommand;
    private checked;

    private dateField = "";
    private maxInterval;

    constructor(args: IScriptArgs) {
    this.args = args.args;
    this.controller = args.controller;
    this.log = args.log;
    }

    public static Init(args: IScriptArgs): void {
    return new APS100_DateControl(args).run();
    }

    private run() {
    const panel = this.controller.GetPanelName()
    this.log.Info("Panel: " + panel);

    if (panel == "APA100EC" || panel == "E") {
    this.dateField = "WWIVDT";
    this.maxInterval = 200;
    } else if (panel == "APA100F0" || panel == "F") {
    this.dateField = "WWDUDT";
    this.maxInterval = 300;
    } else {
    ConfirmDialog.ShowMessageDialog({
    dialogType: "Information",
    header: "Script error",
    message: "Script can only be added to APS100/E or APS100/F. Aborting."
    });
    }

    // Attach events.
    this.attachEvents(this.controller);

    this.log.Info("APS100_DateControl initiated2");
    }

    private checkDate () {
    try {
    const ivdt = this.controller.GetValue(this.dateField);

    var dt = new Date();
    var currentDate = dt.getFullYear() + "" + this.leftPad(dt.getMonth()+1,2) + "" + this.leftPad(dt.getDate(), 2);
    var currentDate = currentDate.substring(2, 8);

    const ivdtNum = parseInt(ivdt);
    const dateNum = parseInt(currentDate);

    // If IVDT - today's date i more than 200, ivdt is more than 2 months ahead of today's date.
    if (ivdt - dateNum > this.maxInterval) {
    let months = (this.maxInterval == 200 ? 2 : 3);
    //Retrieving the user response in a Question dialog
    ConfirmDialog.ShowMessageDialog({
    header: "Date check",
    message: "Invoice date is more than " + months + " months after current date, do you want to proceed?",
    dialogType: "Question",
    closed: (ret) => {
    if (ret.ok == true) {
    this.checked = true;
    this.controller.PressKey(this.lastCommand);
    this.lastCommand = null;
    }
    }
    });
    } else {
    this.checked = true;
    this.controller.PressKey(this.lastCommand);
    this.log.Info("Check OK, proceed with command " + this.lastCommand);
    }

    } catch (ex) {
    this.log.Error("checkDate(): " + ex);
    }
    }

    private leftPad(num, length) {
    var result = '' + num;
    while (result.length {
    this.onRequesting(e);
    });
    this.detachRequested = controller.Requested.On((e) => {
    this.onRequested(e);
    });
    }

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

    private onRequesting(args: CancelRequestEventArgs): void {
    this.log.Info("Command type: " + args.commandType + "; Command value: " + args.commandValue);
    if ((args.commandType == "KEY" && args.commandValue == "ENTER") && !this.checked) {
    this.log.Info("Doing check!");
    args.cancel = true;
    this.lastCommand = args.commandValue;
    this.checkDate();
    } else {
    this.log.Info("Check already done!");
    }
    }

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

    private splitAndTrimArguments (args: string) {
    return args.split(',').map(arg => arg.trim());
    }
    }

    1. norpe

      You cannot call the PressKey method directly from an event handler for the Requesting event. After you cancel the Requesting event by setting the Cancel property to true you need to delay the call to PressKey. One way to do this is using the BeginInvoke method in the dispatcher.

      Example:

      private CallPressKey() {
      this.controller.PressKey(this.lastCommand);
      }

      var action : Action = CallPressKey;
      Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, action);

      1. Jonatan Stenbacka

        Thank you for the quick response!

        However, it doesn’t seem like Action, Application or DispatcherPriority are types available in TypeScript, because I just get “[ts] Cannot find name ‘Action’.”.

        Did you write this solution in javascript or something?

        Thanks again,
        // Jonatan

  52. Jonatan Stenbacka

    Hi!

    So it seems like you can’t call controller.PressKey() directly from an event handler for the requesting event. So how do you do it instead? It seems like you somehow need to delay the call to the PressKey() method, how can you do that?

    It was suggested to me that you use Application.Current.Dispatcher.BeginInvoke. However, it doesn’t seem like Action, Application or DispatcherPriority are types available in TypeScript.

    Thanks,
    Jonatan

  53. ERIC C WAYKER

    Hello Karin

    We still use JScript.NET on our 13.4 ISO Smart Office. I am currently working on moving over those scripts to H5. I have my first h5 script working in my current H5 client. I have successfully deployed the data file via the H5 Administation Tool. I have added to my own user personalization script and it works fine. However when I copy the personalization over to Global personalizations with the H5 Administration Tool I can no longer view/execute the H5 script. Is it possible that JScript and H5 scripting do not play nicely in the same Global personalization?

    1. Karin Portillo Post author

      Hi Eric,
      You cannot combine a user personalization with a global personalization of the same type. That means that if you have a personal personalization of a specific type, like JScript then the Global would not be applied. It’s the same with a personalization on a role for example. The first personalization that is found user, role or global will be used. It does not matter if you have multiple roles with different personalizations. We never merge personalizations of the same type. So you will have to think about and plan for how to deploy the scripts.

      So remove the user personalization and try again. If you still have issues check with Fiddler of the JScript file is loaded in the browser and check the server log for M3 UI Adapter on the grid server to see any message related to loading the script.

  54. Georg

    Hi,

    considering my script consists of following two lines of code in the run method:

    ScriptUtil.SetFieldValue(“W1OBKV”, “99999999”, this.controller);
    this.controller.ListOption(“1”);

    For test purpose I deployed it in MMS001. I can see that the value “99999999” gets set in field “W1OBKV”. But this.controller.ListOption(“1”) creates an empty item with item number blank. I can use:

    setTimeout(() => { this.controller.ListOption(“1”);}, 1000);

    then it works as expected.

    But this is not a good solution since I can’t be sure that the timeout is long enough. Depending on the PC it can take 500-1500ms. Is there a way to check if UI is loaded and perform the List option after this?
    Thanks,
    Georg

    1. Reah

      Hi Georg,
      You can make use of request events and set the field value on the RequestCompleted handler:

      controller.RequestCompleted.On((args: RequestEventArgs) => {
      	if (args.commandType === "LSTOPT" && args.commandValue === "1") {
      		ScriptUtil.SetFieldValue("W1OBKV", "99999999", this.controller);
      	}
      });
      

      If you need more information on request instance events, please have a look at the documentation and the H5SampleRequestTracer and H5SampleCancelRequest scripts included in the SDK package.

      For your reference: 
      The PDF file can be found in 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 

  55. Georg

    Hi Reah,
    thank you for your answer. Unfortunately, it does not work as expected. I have tried already to call this.controller.ListOption(“1”); first and then set the value in the onRequesting or requestCompleted method. But the value I set gets ignored. I have also seen that in the developer console of the browser following error is displayed
    jquery-1.10.2.min.js?v=MTAuMy4xLjAuMzUz:5 Uncaught TypeError: Cannot read property ‘nodeType’ of undefined
    at Function.acceptData (jquery-1.10.2.min.js?v=MTAuMy4xLjAuMzUz:5)
    at R (jquery-1.10.2.min.js?v=MTAuMy4xLjAuMzUz:5)
    at Function._data (jquery-1.10.2.min.js?v=MTAuMy4xLjAuMzUz:5)
    at RenderEngine.InitializeListHeaderContextMenu (mforms.min.js?v=MTAuMy4xLjAuMzUz:1)
    at mforms.min.js?v=MTAuMy4xLjAuMzUz:1
    This error is only thrown if this.controller.ListOption(1); is called directly in the run method. Do you have any idea on this error? Thanks.
    Georg

  56. Ken Eric Gilja

    Hi,

    We been working on a websdk for H5/IOS.
    The requirement was to use multiple CMS010 list panels as part of the solution.
    After failing to bookmark and run a standard listpanel in javascript, we used the “mashup everywhere” and created mashups to be opened directly in the websdk to get the ListPanels working.

    However, when running this in H5 directly it works fine, but when running it in H5/IOS we lose the company/divi when the websdk closes.
    This causes an error when trying to open any M3 standard programs afterwards, until the cono/divi is set again.
    This only happends when we run a bookmarked listpanel through the mashup. And it seems to clear the userContext everytime.

    Does anyone have any experience with the same kind of issue? Or know how to run a bookmarked ListPanel in native javascript for H5?

    Thank you.

    Regards
    Ken Eric

    1. Karin Portillo Post author

      Hi,
      I think that you should report this issue.
      But please note that you need to be extremely clear with the scenario that fails by providing a sample as well as a step by step instruction. For example: Is the bookmarks running in a Mashup, is the webSDK application running mashups, is the webSDK opened within H5 or in it’s own tab? What is the step by step flow? What do you mean with “websdk closes”. I assume that you are executing a bookmarks in the webSDK and at some time the dono/divi on the user context is lost. It appears that you have a fixed scenario that fails so please create a repro and report it. We generally does not support coding issues but if this is something in the webSDK or in Mashups we should have a look at it. Just describe the scenario and provide a repro so that it is clear.

      It needs to be clear what versions you are using; H5, Mashups, WebSDK.

      One of limitations with a shared browser session like we have in H5 is that if you run a webSDK outside of H5, launch H5 and then close H5, the H5 client will logout and the webSDK application will not be able to continue as the session is no longer valid.

  57. Christian Heggen

    Hi.
    Does anoyone know if it possible to detect how many programs that are open in the H5 session?

    1. Karin Portillo Post author

      Hi Christian, this information is only available on the server and there is no method that the client can call to get the full list of open programs. It gets more complicated as there can potentially be Mashups, WebApplications created with the SDK, as well as the H5 client that are containing open programs.

      Regards
      Karin

    1. Reah

      Hi Jonatan,
      You can use the helper class MIService for executing M3 API requests. Please refer to the dev guide for examples.
      For other REST endpoints, you can easily perform AJAX requests.

  58. Kat

    Hello,

    I am trying to set a value for dropdown field OAOPRI in OIS100/I , using ScriptUtil.SetFieldValue(“OAOPRI”, “9-Low priority”); but it blanks the field value. I also tried this $(“#OAOPRI”).val(“9-Low priority”).change(); but still no luck. is there any another way to set the dropdown field value? Thank You.

    Regards,
    Kathir

    1. Reah

      Hi Kathir,

      Can you please verify that the value you are setting to is available in the list? Also that “9-Low priority” is the option val, not the text.

      Thanks.

  59. Kat

    Hello,
    I have a requirement that when we click a button it should open the browse window(with the pagination and select option) like in standard F4 browse window in M3 and on selecting a row from browse window it should populate the selected value on a screen field. is there any way we can achieve this requirement in H5 script / jquery ?

    Thank You.
    Best Regards,
    Kat

  60. HeikoM

    Hi,
    I am developing a H5 (Typescript) solution which runs on a M3CE Multitenant environment. What is the correct Start Url in Visual Studio ? I assume that I am not able to access the ..\mne folder due to security reasons. When I use the mingle/portal-logon, I can log into M3, but debug is not enabled.
    Best regards
    Heiko

    1. rajithawi

      Hi,
      Have you able to sort this out?
      I’m facing the same issue, When i set the mne path it will open the H5 client from visual studio but debug is not enabled.
      Please advice.

      Regards
      Rajitha

      1. Reginald Reyes

        Hi,
        When I’m using H5Scripts in M3 Cloud Environments, I use VS Code as my IDE and installed a “Debugger for Chrome”.
        Here are the steps I do:
        1. Run M3CE Mingle – > Open H5 Client
        2. Open Stand alone of M3CE H5 Client (open in new browser tab, don’t close Mingle)
        -attach the localscript parameter ex. (https://m3devapp.m3cedev.awsdev.infor.com/mne/?localScript=http://localhost:8085/H5SampleHelloWorld.js“)
        3. Run Webserver of my H5Scripts then Run chrome debugger in my VS Code
        4. It will now work

        Here is my configuration in “launch.json” of debugger for chrome:
        “configurations”: [
        {
        “type”: “chrome”,
        “request”: “attach”,
        “name”: “Launch Chrome”,
        “url”: “https://m3devapp.m3cedev.awsdev.infor.com/mne/?localScript=http://localhost:8085/H5SampleHelloWorld.js”,
        “port”: 9222,
        “sourceMaps”: true,
        “webRoot”: “${workspaceFolder}”
        }
        ]

        *I hope it will work for you too

        Regards,
        Reggie

      2. rajithawi

        @Reginald Thank you for your response.
        I have configured the “launch.json” as you described below and place my .js file under the folder structure. Once I launch it from debug mode it will open the H5 but again not hit the debug points.
        Can you please clarify point no : 3 (Run Webserver of my H5Script) further more.

        Thanks

      3. Reginald Reyes

        Hi raji,
        Maybe you were using “launch” type of chrome debugger.
        My configuration is set to “attach” and needed to open the mingle H5 Client first and also open the stand alone H5 client version.
        When using attach, the url you set needs to be open before running “debugger for chrome in VS Code”

        /Reggie

      4. rajithawi

        Hi Reggie,

        Thanks for your guidance.
        This worked for me with below configuration.
        Now debugger is enabled.

        {
        // Use IntelliSense to learn about possible attributes.
        // Hover to view descriptions of existing attributes.
        // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
        “version”: “0.2.0”,
        “configurations”: [

        {
        “type”: “chrome”,
        “request”: “launch”,
        “name”: “Launch Chrome against localhost”,
        “url”: “https://m3use1.m3.inforcloudsuite.com/mne/?scriptCache=false&localScript=http://localhost:8085/H5AddButton.js”,
        “sourceMaps”: true,
        “webRoot”: “${workspaceFolder}”
        }
        ]

        Thanks
        Rajitha

  61. Deepak

    Hi All,
    i have a requirement to highlight a cell from grid(subfile) on some conditions. Can anyone help me in this?

    1. Peter Grew

      Hi Deepak,
      The conditions required to highlight the cell, are they outside the scope of what can be handled by the tool found in the menu option “Tools -> Personalize -> Conditional Styles…” in the H5 panel? In case you have missed that option I recommend that you have a look at it.

  62. Marcus

    Hi,
    I have a problem when trying to validate project numbers in OIS100 on the E-panel with the help of a script, the problem seem to be that the program does not wait for the results of my validations before continuing to the F-panel. Error messages and everything is displayed but the program still continues to the next panel.

    To stop the program if the validation fails I use args.cancel as used in the H5SampleRegexValidator sample code that comes with the H5ScriptSDK, it works just fine as long as I do not include values fetched from MIService. When doing this the execution of the main program simply ignores my args.cancel, I have tried using async/await and different variations of Promis but nothing seem to work.

    Anyone else having this type of problem?

    Current version of the UI adapter: 10.3.1.0.369

    Thanks / Marcus

    1. Karin Portillo Post author

      Hi Marcus,
      The way you describe it you would have to set cancel directly, before doing any other calls. If it does not work when you call a MI Service that is because that call is asynchronous. You need to make sure you call cancel even if you don’t know yet that you need to cancel. Does that make sense?

      1. Marcus

        Hi Karin,
        Thanks for your quick reply, it does make sense in a way even though it would have made more sense for the application to support the async/await. I’ll do some more tests with the cancel call at the beginning before anything else is called.

        Thanks / Marcus

      2. Marcus

        Hi again,
        Still in OIS100 on the E-panel.

        Is there any way to capture the event on the next button other than command value Enter, I have encountered an issue where my script is overriding the standard project number validation for the order type. It is the initial args.cancel = True that is causing that validation to not work any longer, it seems as the panel gets stuck in a status where the basic validation of the field should have displayed an error message but now isn’t and that the validations from the script is not triggered because the project number added does not exist.

        Optionally if there is a way in the script to determine if the basic validations on the program and its fields are done before the validations in the script are triggered, I have gone through the documentation and cannot seem to find any examples on what I am looking for.

        Thanks / Marcus

      3. Tjalve Morken

        Hi Marcus,
        You may do whatever you like in the script BEFORE the Enter-key sends the control to the BE-program behind the panel – the program doesn’t know what goes on in the script until you press the Enter-key (or a F-key, open related etc).
        When the program does it’s validation, it also takes control over what happens next (like showing another panel).
        So you have to do “your stuff” before the program takes control (by cancelling the Enter-key event).
        To avoid getting in a situation where “nothing happens”, you have to simulate the Enter-key after your validation-logic (if you don’t show an error-message and want the process to stop).

      4. Marcus

        Hi Tjalve,
        Thank you for the answer, I got it working by returning true from the validation functions in those cases where validations where not suppose to be taking place. By doing that the validation in BE triggered as expected so the two could be combined.

        Thanks / Marcus

      5. Reggie

        Hi Marcus,
        If you have an attached “Requesting” event on the controller, you can always capture/override the event that needs to be cancelled, just as Tjalve said, you should first validate and do your stuff before that program takes control.

        Regards,
        Reggie

    2. HeikoM

      Hi Marcus,
      as the MI call is asynchronous as Karin stated, you need to synchronize background call and user activity. Before the MI call is started, set a global flag. When the user presses a key, check if the MI call is still executing. If so, cancel the requesting event and set a second flag and the action that the user has chosen – probably you only have to react to “ENTER”. When the MI call finishes, do your validation. If the entry was correct, and your second flag indicates that the user has already pressed ENTER before the MI call finished, do it now programmatically. If the entry was not correct, you have already cancelled the event, so present a message to the user. If the user presses enter at a time where the MI call already finished (indicated by the flag that you have removed), everything runs as usual.

      1. Marcus

        Hi Heiko,
        Thanks for you r quick reply.

        The thing is that I only calling the validation function when the user is pressing enter, I have that as a condition because the user can change the project number so I can only validate the field when he tries to move forward. I therefore have the validation call inside the onRequesting function where I am verifying that the user mode, this.controller.GetMode(), is 1, 2 or 3. If that is the case and the user has pressed Enter, args.commandValue === “ENTER”, I then call the actual validation which also includes the async MI calls.

        All logic is in other words only triggered when the user is hitting Enter, not really sure how to check the status of the validation function (including MI calls) inside the onRequesting function, the only way in there to the logic is for the correct mode to be used and that the user has pressed Enter. Because the user can change the project number I cannot trigger the validation unless he is trying to move forward via Enter or Next and in the user mode to do so.

        Am I approaching this all wrong, I do not want anything validated or cancelled if the user is only viewing the information on the E panel.

        Thanks / Marcus

      2. HeikoM

        Hi Marcus,

        I think I understand. In that case you must cancel the request, wait for the API having finished, and then press enter programmatically if the validation is ok.

        Of course this must only be done if the user changed the project number. Buest guess is to read the project number from the screen when the panel opens and compare it to the value when the “Requesting” event is fired. And of course you must check the mode as well and do this validation only on Create, Change and Copy.

        This event’s argument (of type CancelRequestEventArgs) has a “Cancel” property which can be set to “true”.

        The H5 Development Guide has sample code for controller event handling.

        Logik:
        in “Requesting”:
        if the mode is “display” or “delete” => do nothing
        if flag detects “pressed by script” => do nothing, but reset the flag
        if the user did not change the project number => do nothing
        if new project number => cancel the event and run the API
        in your “API completed” handler:
        if valid project number => set flag “pressed by script” and press enter
        if invalid => message to user

        the flag can be stored in the InstanceCache. After pressing enter programmatically, your script will reload and lose all variables.

        It is also a good idea to save valid project numbers in the cache (Session cache, if they are immutable, otherwise Instance Cache) and compare the values. If it is a valid project number which has been validated in a previous API call, no new API call is required.

        br
        Heiko

      3. Marcus

        Hi again,
        It is now working by the looks of it when using the cancellation right at the gate and then passing the Enter after the validations, thanks for the help it was really helpful.

        Thanks / Marcus

  63. Pra

    Hi
    Can anyone give me a code sample to file open dialog and read some text files ?

    I could not find any solution on web.

    Help is appreciated .

    Thanks
    PRA

    1. Karin Portillo Post author

      Hi,
      I’m not sure what the scenario is. SoHo Xi has a file upload control that would allow you to browse to a file. It’s used in the H5 admin tool to import files.

      But the content of the file can only be posted to a server. You can’t just write JavaScript and access files on the computer. You can only upload data as a form post for example.

  64. Ian A

    Hello!
    I’m trying to populate editable fields in a listview with data. Unfortunately it is not the first row. Is there a way to move to say the third row to populate the data and column XXXX?

    1. Peter Grew

      Hi Ian,
      This piece of script will change the text in the editable cells of a list.

      import System;
      import System.Windows;
      import System.Windows.Controls;
      import MForms;

      package MForms.JScript {
      class EditableCellUpdate {
      public function Init(element: Object, args: Object, controller: Object, debug: Object) {
      var listControl = controller.RenderEngine.ListControl;
      var items = listControl.ListView.Items;

      debug.WriteLine(“Script Initializing.”);

      for (var r = 0; r < items.Count; r++) {
      var row = items[r];

      for (var c = 0; c < row.Items.Length; c++) {
      var cellText = "Cell " + r + ", " + c;
      row[c].Text = cellText;
      debug.WriteLine("Set value for editable " + cellText);
      }
      }
      }
      }
      }

  65. Prabodha

    HI
    How to populate editable fields in a listview with data using H5 scrpits .
    I have tired one way but to update date in the cell i want to click the cell .
    Thanks
    PA

  66. Promethius

    Can somebody please help me with programatically entering CTRL+27 in a type script?

    Thanks

      1. Promethius

        Thank you very much, that worked! Is there any way to declare a global variable within an H5 script that will be seen from within an MIService execution block? Meaning, when I exit the MIService block it will retain the value set within the block:

        MIService.Current.executeRequest(myRequest).then(
        (response: IMIResponse) => {
        //Read results here
        for (item of response.items) {
        asid = item.ASID;

        if (asid !== “” && asid !== “undefined”) {
        ConfirmDialog.ShowMessageDialog({ dialogType: “Error”, header:
        “ERROR”, message: “my message” });

        }
        else {
        //send CTRL+27 programmatically
        //SET A GLOBAL HERE THAT WILL BE ACCESSIBLE OUTSIDE OF THIS REQUEST
        this.controller.ListOption(“27”);
        }
        }
        })

        Thanks!

      2. Tjalve

        Hi Promethius,
        Yes, this is absolutely possible.
        But the “trap” here is that the api is run asyncroneously, meaning that the rest of the code will continue while your codeblock is waiting for the response from M3.
        Thus there is a possibility that you will try to access your global variable before it is set inside your MIService-block.
        One way to solve that, is to use async and await (calling the async method and waiting for it to finish before continuing with the rest of the code).
        This way you are guaranteed that the MIService-block is finished before you try to access the global variable.

        Kind Regards,
        Tjalve.

  67. Ahmed Taha

    How can I read from the environment profile some parameters like the smart office Jscript using H5 scripts

    1. Tjalve

      Hi Ahmed,
      You mean the UserContext?
      If so, you can e.g. write:
      const userContext = ScriptUtil.GetUserContext();
      let cono = userContext.CurrentCompany
      And so on for all parameters of the Usercontext.

      1. Ahmed Taha

        Hi Tjalve, I meant the application services which is under the environment profile for smart office where you read the parameters related to some application components like PF and Mashup web services configuration

      2. Ahmed Taha

        Hi Tjalve,
        I meant the application services which stored in the environment profile for the smart office where you retrieve the parameters related to the application components like PF, Mashup or web services

  68. Ahmed Taha

    here an example for what I am trying to have
    validAgreementType =ApplicationServices.SystemProfile.GetProperty(ApplicationGroupType.PF, “PFlow”, “ValidAgTypes”);

    1. Karin Portillo Post author

      H5 does not have any PF configuration data. You will need to have the base URL as a parameter to your script. I don’t think that you will be able to call PF if that is your goal. The cookies the browser has are not valid for PF and you can’t have user credentials in the script. What is the scenario? Where is PF installed? Is it in the same grid? If it is then you should just have a relative path. If it is not on the same grid you have an issue and am not sure how you would be able to access it. Also unless PF supports CORS (cross domain calls) then you would not be able to call them from a browser loaded from another server than the PF server.

      1. Ahmed Taha

        I am trying to generate IPA workflow using HTTP request but it doesn’t recognize the user and password and I don’t know the parameters that I should send as per the below example
        let uri = ‘http://pztjhipa.zahid.com/sso/SSOServlet?_ssoUser=IPA_EJAR^&_ssoPass=”Password”&_action=LOGIN^&_fromLoginPage=TRUE^&_language=en-us^&_locale=en_US^&_ssoOrigUrl=http://ppzjhipa.zahid.com:80/bpm/trigger?triggerType=ServiceAsync&triggerName=IPA-PPW-004-Serv&dataArea=lpa_data_psu&workTitle=’ + data + ‘&varName\[0\]=DONO&varValue\[0\]=’ + data + ‘&varName\[1\]=Originator&varValue\[1\]=’ + encodeURI(this.usid.toUpperCase()) + ‘&varName\[2\]=ToWHS&varValue\[2\]=Y30&varName\[3\]=strCompany&varValue\[3\]=’ + encodeURI(this.Company);
        ScriptUtil.Launch(encodeURI(uri));

      2. Karin Portillo Post author

        Hi,
        I don’t know how to integrate with IPA. NEVER pass a user and password. You need to solve this in another way. I suggest using the enhancement request process or contact the product owner Ole Rasmussen for a discussion. Never have secret information in a JScript or JavaScript. It’s visible to everyone. Passing information over http is also visible to everyone. It’s not acceptable do do these kind of tricks. You shouldn’t even have sensitive information in the Smart Office profile.

        Sorry.

  69. Kevin Zhang

    Hi,
    I am trying to develop type script so M3 H5 can call external(another domain) Web Service API to retrieve data and push them back to M3 using $.ajax()…got the error:

    No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘https://xxx.domain.com:20110’ is therefore not allowed access.

    Where to setup M3 Grid and so it can allow CORS request?

    1. Karin Portillo Post author

      It is the other server that has the service that prevents the call. Is that an Infor Grid? CORS is not configured grid wide but on a context root. Contact support for the application you are trying to access.

      Regards
      Karin

  70. Dax

    Hi

    Is there a way to create a button that lets users select an excel file? and then the records in that file gets sent as input parameters to an MIService call?

    Help much appreciated. Thanks!

    1. Karin Portillo Post author

      Hi,
      No. JavaScript don’t have access to the client’s disk.
      I would only work if the Excel file is accessible through a URL (https/http) and CORS script access is allowed. In order to access a file on a client’s machine you will need to post it to a server, which you don’t have if this is a H5 script. The only workaround would be to copy and paste the content of the excel file into a dialog where you have a text area, but that is not good user experience.

      1. Dax

        Hi,

        Is there a way to use in an h5 script?
        The reason I’m asking is because I need to convert a jscript which is used for importing excel data into a db table. In that jscript, they use System.Windows.Forms.OpenFileDialog().
        Is this still possible in h5 script?

        Thanks!

      2. Dax

        Hi,

        Is there a way to use “input type=file” in an h5 script?
        The reason I’m asking is because I need to convert a jscript which is used for importing excel data into a db table. In that jscript, they use System.Windows.Forms.OpenFileDialog().
        Is this still possible in h5 script?

        Thanks!

      3. Karin Portillo Post author

        Hi Dax,
        I thought of this some more it’s possible to load a file in Chrome, but I don’t know if an excel file could be opened or not. Generally we don’t develop something that would only work in Chrome. In web there is a corresponding Infor Dialog control that you can use to create your own dialog, search for dialogOptions in the comments on this page.

        You can’t import anything into a DB table, you can call MIPrograms but you are not allowed to have any sensitive information which means calling a DB is not an option.

        Basically what you are looking for would need an endpoint which you could post the excelfile too that would then return it’s data to the script. That would work in all browsers as long as that endpoint allow cross site scripting.

  71. Kirill

    Hi Karin,

    I call M3 API in H5 script like this:

    MIService.Current.execute(program, transaction, record).then(function (response) {
    console.log(“API works fine”);
    }, function(err) {
    console.log(“oops, something is wrong err”);
    });

    Is there a way to see error message returned by API?

    Thanks,

    1. Karin Portillo Post author

      Hi,
      I’m not sure exactly what you mean? Do you mean in case of a NOK? It’s part of the response. If you debug in the browser dev tools you can check the object in the debugger. I don’t remember if we have typings right n place for the response, but I think we do, I’ll check tomorrow.

      1. Prabodha Amarapema

        Hi

        Is there anyway to hide a column in a grid dynamically or make the editable cells as read only

        Thanks
        Prabodha

  72. Prabodha

    Hi
    Is there any way to hide column in grid dynamically using J script?

    Or disable editable cell
    Thanks
    Prabodha

  73. Dax

    Hi,

    When opening a modal window using dialog options, how do you get the properties declared in the parent window and use the value in this modal window? I’m always getting ‘undefined’.

    Thanks!

    1. Reginald Reyes

      Hi,

      You should always get the value you want to pass from the instance controller and get the parent window/host.

  74. Deepak Jadhav

    Hi,
    Is there anyway to add a dropdown or combobox in H5 which will be populated by fetching records from API(MI)?

    1. Karin Portillo Post author

      Hi,
      Yes it is possible. It’s a matter of adding the correct control. What is the user case? Replacing an existing input field? Because that might not be possible.

      1. Deepak

        Yes there is a textbox and that needs to be replaced by combobox. Can you provide the script for adding a combobox/dropdown field?

      2. Reginald Reyes

        Hi Deepak,

        You can do like this.
        let buttonElement = new CheckBoxElement();
        let contentElement = this.controller.GetContentElement();
        contentElement.AddElement(buttonElement);

        You can also create an instance of CheckBoxElement like the textbox and add it using “.AddElement”

  75. Jessika I

    Hi,
    Looking around I see values on M3 panels retrieved both with ScriptUtil and this.controller. What are the pros and cons? When is it better to use one rather than the other?

    Examples which both work for me:
    let DAField1 = ScriptUtil.GetFieldValue(“WWALVL”)
    let keyField1 = this.controller.GetValue(“WHITNO”)

    1. Reginald Reyes

      Hi Jessika,

      Technically you can use both, because it goes to the same code base, but it is best to use the ScriptUtil because the utility is made primarily for scripts, plus it can carry an instance controller parameter that is “mandatory” to pass when using scripts in webmashups.

  76. Sunny

    Hi
    Is there a way to know if the user is in display mode or change mode in H5 ?

    Thanks
    SP

    1. Reginald Reyes

      Hi Sunny,
      You can check the panel response if the mode is “2” for change and mode “5” for display.
      //Reggie

  77. Kevin Zhang

    Is it possible to change entire row text color or background color based on certain cell value in grid list using H5 script?

    Thanks
    Kev

  78. rajithawi

    Hi,

    I’m looking for a way to read the M3 error/ Warning messages while MForms automation running.
    Seeking your ideas is this possible or if there any work around.

    Thanks

    1. Karin Portillo Post author

      Hi,
      There is no way to do this with automation.
      What are you using the automation for? I checked with my colleagues as well. Will you ever present a screen from the automation? Perhaps a bookmark would be a better option?

      1. rajithawi

        Hi,
        Thanks for your prompt response.
        My requirement is to upload excel file and based on number of lines in excel file, I have to create lines in M3.
        Automation has proposed because there are no standard M3 API to fulfill my need.
        So as I mentioned before while creating the lines via automation, I need to keep a track if any error occurred.

        Thanks

    2. Karin Portillo Post author

      Hi,
      Basically you need to have an API for this. There is also a lot of limitations with the actual file upload in a browser when you are not actually posting the file to the server, that I have written comments about in the past.

      1. HeikoM

        Hi,
        Basically the JavaScript File-API allows to access files from the local machine after the user has selected it or it has been dropped to a special region on the HTML5 UI.
        Then GLS840MI can be used to process finance data which are defined in GLS850 as a template (interface type 1; takes a 900 char parm field which holds the input data in a structure which is described in the GLS850 input record) or, in M3CE, even as interface type 2, where each M3 field is exposed as parameter which can be passed to the REST API call.
        An alternative is to run the solution standalone outside the browser or as Excel AddIn.
        /Heiko

  79. Tjalve

    Hi,
    In H5 you can show programs “side by side”.
    (Start two programs, then drag one tab over the other and they are shown “side by side”).

    A lot of the functionality in scripts seem to stop working in the “second tab” when using this functionality.
    E.g. ScriptUtil.GetFieldValue and SetFieldValue does not find the fields in scripts on the second tab.
    It looks like the error is because the “Active controller” always points to the controller in the first tab (even for scripts in the second tab/program).

    Is this drag/drop of tabs offisially supported in H5 – and in that case: is this an error in the H5 ScriptUtil functionality?
    /Tjalve.

  80. Karin Portillo Post author

    Hi, This should be corrected. It is possible that a new ScriptUtil that takes the controller as a parameter is needed in this case, eg, it can’t be static. The ScriptUtil was created when there could only be one instance. I’ll create a ticket to add a new method on the ScriptUtil and ask that the other methods are deprecated.
    If you would like to track this please add a ticket through support and we can connect those tickets.

      1. Karin Portillo Post author

        This is not a bug that we can just fix. Code changes in the scripts will also be needed as the ScripUtil needs to resolve using the current instanceController as a parameter or similar.

      2. Tjalve

        Yes, of course.
        A parameter with the current instanceController sounds like a good idea (and deprecate the current function)

  81. Siemen Blok

    Hi there,

    I’m really new to H5, M3 and JS but just started as developer and got asked if I could write a script that launches an URL to a mashup. Now I’ve figured that part out but I’d like to make it a bit better. When the mashup is launched I’d like to select a field in the DataGrid (Slick-grid). I can’t seem to get that working and I don’t know why. Could anyone help me with that? If my question is unclear please tell me, I’m really new to it all.

    1. Reginald Reyes

      Hi Siemen,
      I just need to clarify if the script that you attached in a program launches/opens a mashup and have a different tab? and you are hoping to select something after that mashup loads?

      note*
      For every program there will be an instance, which mean even if you have a set of mashup, those mashups that run different programs will also have different controllers.

      /Reggie

      1. Siemen Blok

        Hi Reggie,

        The mashup loads in a different tab and I would like to select something after the mashup is loaded. So the script is attached to a shortcut in a program (lets say mms001). When the shortcut is clicked it should fire an URL to a mashup of mms001 and some other stuff. Is it possible to make the mashup launch in the same window/tab?

  82. Dax

    Hi, I’m trying to call infor webservices via H5 script, but we are getting a CORS policy issue.

    I’m getting “Access to XMLHttpRequest from origin has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.”

    Is there any way to work around this issue?

    1. Karin Portillo Post author

      Hi Dax,
      Is Infor Web services and H5 in the same Grid? This is in a JavaScript right? I would not call it work around but you need to configure Infor web services so that it allows Ajax calls from the domain that is loading the script you are writing. This has to be the external address that you use to access the application. What exactly is the scenario here? It’s possible that there is configuration that you can do, some domain whitelist in Infor Web Services. Have you checked it’s documentation?

      1. Dax

        Hi Karin,

        Yes, this is in a javascript. I’m using XMLHttpRequest to call the webservice, instead of AJAX.

        We’ve already tried to add the domains in mi.cors.allowed.domains property in the Grid settings, but still facing same issue.

        Do we need to add/do something to the infor webservices to allow requests coming from the origin?

        Thanks!

    2. Karin Portillo Post author

      Hi,
      mi.cors.allowed.domains Sounds like a setting för MI-WS (M3 API) and not Infor web services. Yes, a configuration is beredd but I’m afraid I don’t know explicitly what to set.

    3. Karin Portillo Post author

      Hi,
      I’ve checked and Grid 1.13 and Infor Web Services (MWS / LWS) does not have CORS support. So you can only call it from client code running in an application on the same host. Your only option would be to create a M3 MI Program and all MI-WS as it supports CORS.

      Where are you executing the script call from?

      1. Dax

        Hi,

        I also suggested to create a M3 MI program for it instead. But they said that they are using IWS because they have complicated SQL queries which require to join multiple tables. DO we have any alternative for querying into multiple tables?

      2. iamaj

        Hi Dax,

        You can consider setting up an information category in CMS010 and its related tables. This can be used in CMS015 to setup a transaction in CMS100MI. Returned fields are setup in CMS010->views, which are also selected in CMS015.

        Cheers,
        Jonathan

  83. Dax

    Hi,

    Why is it that when I use this.controller.GetContentElement().GetElement(‘XXXX’).readOnly() it also disables the field? I’m asking because I need to set a field as readonly and pass the value for that field to the next panel. But what happens is readOnly() also disables the field, thus the value doesn’t get passed.

    Any thoughts on this?

    1. Reginald Reyes

      Hi Dax,
      When using “this.controller.GetContentElement().GetElement(‘XXXX’)”, you are selecting an element from your current panel, and if you’re going to get the value from that element(textbox), you need to add “.val()”
      ex.
      this.controller.GetContentElement().GetElement(‘XXXX’).readOnly()
      -This will only disable the field
      this.controller.GetContentElement().GetElement(‘XXXX’).val()
      -This will get the value from the selected element

      /Reggie

  84. Siemen Blok

    So in the hope someone can still help me I’ll post my question again. I’m trying to launch a mashup in a different tab and to get a value in a field en make it so that the value entered in the field is also selected from the Slick-Grid that is part of the mashup. Can anyone help me in a direction?

  85. iamaj

    Hi,
    Has anyone tried uploading a file from a H5 javascript of web SDK to IDM?
    From what I understand, the user has to select the file via the browser will pass it to the javascript, and then converted to a stream to send to an IDM API, with appropriate tags in XML.

    Is this correct and does anyone have details?

    – Jonathan

  86. Marcus S

    Since one of the last updates of H5 it seems no longer possible to format text in dialog windows that can be called with “ConfirmDialog.ShowMessageDialog()”.

    For example earlier it was possible to control line break and add bold text. Now with the new H5 version the whole HTML code is written to screen. It would be really good if it was possible to at least do a line break to be able to format the text that the user is shown.

    Any suggestions?

    Example code:
    ConfirmDialog.ShowMessageDialog({
    header: “Test of dialog”,
    message: “This is an example test with BOLD text and a line break here second line”,
    dialogType: “Information”
    });

    1. Karin Portillo Post author

      This is actually a security correction. The message should only be text and since the content can’t be trusted it’s now escaped. You can add an enhancement request to support something like wiki syntax in the text for formatting of this component or you would need to create your own message dialog by using the Infor Design Control and if you know that the text is completely hard coded and does not contain anything that is dynamically created or input from a user then you can add your own HTML and handle it as HTML.

      Cross Site Scripting vulnerabilities should be taken extremely seriously and it is something that you need to think about in your code as well if you are handling any type of data based on user input.

      1. Marcus S

        Thanks Karin for the answer!
        I understand the reason behind the correction and I like the idea around the wiki syntax. I will investigate if I can implement a custom message dialog instead.

  87. Siemen Blok

    I have a problem, my code is as follows:

    var populateData = function(list, columnNum){
    var columnID = “C” + columnNum;

    for(var i = 0; i {

    /* LOGS SECTION:
    console.log(“Response Request “);
    console.log(response);
    */
    userStatus = response.items[0].USTA;
    console.log(userStatus); // Shows the right value
    });

    var newData = {};
    newData[columnID] = “DUMMY DATA ” + i + ” ” + userStatus; // Shows “unknown”
    newData[“id_” + columnID] = “R” + (i+1) + columnID;
    $.extend(list.getData().getItem(i), newData);

    /* LOGS SECTION:
    console.log(“newData”);
    console.log(newData);
    */

    }
    var columns = list.getColumns();
    list.setColumns(columns);
    };

    I was wondering if anyone has a tip on how to get the userStatus in the later part of the code assigned the value retrieved with the API call. Any other comments on my code are also greatly appreciated since I don’t have much experience.

    1. Siemen Blok

      It seems certain parts of my post have been scrubbed, forgot about sanitization. Here’s the right version i hope:

      /*var populateData = function(list, columnNum){
      //var columnID = “C” + columnNum;

      //for(var i = 0; i {

      /* LOGS SECTION:
      console.log(“Response Request “);
      console.log(response);

      userStatus = response.items[0].USTA;
      console.log(userStatus);
      });

      var newData = {};
      newData[columnID] = “DUMMY DATA ” + i + ” ” + userStatus;
      newData[“id_” + columnID] = “R” + (i+1) + columnID;
      $.extend(list.getData().getItem(i), newData);

      /* LOGS SECTION:
      console.log(“newData”);
      console.log(newData);

      }
      var columns = list.getColumns();
      list.setColumns(columns);
      };*/

  88. Siemen Blok

    Apperently parts of my code are blocked/sanitized. I have the following problem:

    variable userStatus = “unknown”
    API-call
    userStatus = response.items[0].USTA // gives me the right values.
    newData[columnID] = userStatus // contains the value “unknown” instead

    1. HeikoM

      Could it be that you API-call is async and newData[columnID] is executed before the API finishes? That is not clear from your snippet.

      1. Siemen Blok

        Hi HeikoM, thanks for your quick reply. The API-calls are async but I thought that I fixed that with:

        /*
        async function executeRequest(APIRequest){
        var response = await MIService.Current.executeRequest(APIRequest);
        return response;
        }
        */

        The snippet is not complete since it has been scrubbed of certain functions, my bad.

        It would seem that the newData[columnID] is executed before the API finishes. If this is not the way to go about it, do you have a suggestion?

      2. HeikoM

        The async execution means that you MUST carry on in the same thread of the MIRequest, the main thread does not know that you called something in the function which runs in the background, it continuoes directly with the next statement. In theory you could use promises in the main thread, but I was not capable to got it working in H5. So, alternatively, you need to finish your main routine after “executeRequest”, and move the remaining code to a new routine which you call as last action inside “executeRequest”. This avoids the “Pyramid of Doom” which was a problem in JavaScript before Promises have been invented.

  89. sanyukta2017s

    I am trying to run mforms automation to open OIS103 from OIS100/F panel. it works but the order number with which it opens is a wrong one and not the current one. Maybe it caches one order number and after that only uses that order number to open OIS107. How do I use the current order number? The order number and customer number on the OIS107 is greyed out. Is that the issue? But how does it come correctly the first time?

    My code –
    const auto = new MFormsAutomation();
    auto.addStep(ActionType.Run, “OIS103”);
    auto.addField(“ZZORNO”, orno);
    auto.addField(“OKCUNO”, cuno);
    auto.addStep(ActionType.Key, “ENTER”);
    const uri = auto.toEncodedUri();
    ScriptUtil.Launch(uri);
    Thanks a lot for the help!
    Sanyukta

  90. sanyukta2017

    Hi all,
    I am trying to call OIS103 from OIS100/F panel. OIS103 successfully opens but with a wrong order number. The first time I did this, it worked but after that its the same order number OIS103 is opening with. Looks like this number is cached.My code is
    const auto = new MFormsAutomation();
    auto.addStep(ActionType.Run, “OIS103”);
    auto.addField(“ZZORNO”, orno);
    auto.addField(“OKCUNO”, cuno);
    auto.addStep(ActionType.Key, “ENTER”);
    const uri = auto.toEncodedUri();
    ScriptUtil.Launch(uri);
    Order number is greyed out in OIS103. Is that a problem?
    Appreciate quick help!
    Thanks and regards,
    Sanyukta

    1. macalat

      Hi,

      MFormsAutomation will not work on protected fields. You will need to call OIS103 from the calling program. Your automation should either start with OIS100 or OIS300 and then call related option 12 (Charges)

      1. Sanyukta Kumandan

        Hello Macalat,
        Thank you for the response. You are right. I did this in another way which worked.
        I used the bookmark URI to launch OIS103. Here is my code.
        let bookmark = “bookmark?PROGRAM=OIS103&TABLENAME=OOCHRG&KEYS=OECONO%2C” + CONO + “%2COEORNO%2C” + orno + “%2COECRID%2CSHPFEE%2B%2B%2COEDLIX%2C0%2COEWHLO%2C%2B%2B%2B&OPTION=1&PANEL=E&SORTINGORDER=null”;
        ScriptUtil.Launch(bookmark);
        Sanyukta

  91. Dax

    Hi,

    When I attach a script to a program, how can I use this same script in the other panels of the program without having to attach the script for every panel?

    For example, I attach a script in MMS001/B -> I go to Change mode which will trigger a specific function in the script -> program goes to E panel -> I press ENTER which will trigger a different function in the same script -> program goes to F panel -> script is unloaded.

    Is this possible in H5 script? Because this works in LSO jscript.

    Thanks!

    1. macalat

      Hi,

      H5 script and LSO jscript should have the same event lifecycle (i.e. OnRequesting, OnRequested and OnRequestCompleted), so if you managed to make this work before in Smart Office via Jscript then it should also be possible in H5.

      I wouldn’t personally advice this approach, though. A script’s activity should only be on the panel on where it was attached. Once it is out of that panel, all event listeners for that script should be terminated. Memory leaks and a lot of unwanted behavior would happen if you don’t managed the proper detaching or unloading of the script. It would be better if you create one script for Panel E and another for Panel F.

  92. Pong

    Hi all,

    I am looking to create a script for double confirmation when user trying to print a report.
    The closest thing I have found is H5SampleCancelRequest.
    However when i tried to use ConfirmDialog, the onRequesting method proceed without waiting the dialog to popup. However thing works when I changed to use window.confirm, but since the window pop up box design is different with ConfirmDialog, so I am looking for chance to use ConfirmDialog to achieve the same thing.

    The code is as follows:
    private onRequesting(args: CancelRequestEventArgs): void {
    this.log.Info(“onRequesting”);
    if (args.commandType === “KEY” && args.commandValue === “F12”) {
    return; // The user should be allowed to go back
    }

    if (args.commandType === “KEY” && args.commandValue === “ENTER”) {
    ConfirmDialog.Show({
    header: “Question”,
    message: “Please confirm to proceed”,
    dialogType: “Question”,
    closed: respond => () => {
    args.cancel = respond.cancel;
    }
    });
    }
    }

    Thanks!

    1. Reggie

      Hi!
      I did a lot of different methods, but I only came up using this work around code.

      let _this = this;

      if (args.commandType === “KEY” && args.commandValue === “ENTER”) {
      args.cancel = true
      ConfirmDialog.Show({
      header: “Question”,
      message: “Please confirm to proceed”,
      dialogType: “Question”,
      closed: (respond) => {

      if(respond.ok){
      _this.unsubscribeRequesting();
      _this.controller.ExecuteFunction({CMDTP:args.commandType, CMDVAL: args.commandValue});
      }
      }
      });
      }

      Firstly we need to cancel the current event and re-issue the event after pressing the “ok” button inside the dialog. You also need to unsubscribe the listener first because it you will have an infinite loop if you don’t.

      //Reggie

  93. Ashok Kamble

    Hello,
    How to user inforListBox, can you please share some sample code.
    Thank you in advance.

    1. Reggie

      Hi!

      First you need to create a select element for the listbox.

      ABC Manufacturing
      Acme Industrial

      Then on your script file, you need to initialize the listbox.
      $(“.inforListBox”).inforListBox({showCheckboxes:true});

      Then when doing an event it should look like this.
      For example when deleting all the options inside the listbox, of course you need a button for it to work.
      $(“#listbox1”).inforListBox(“clear”);

      //Reggie

  94. Jonatan Stenbacka

    Hi! Is there a way to make the text in a column act as hyperlinks? In my case I want the user to press the text in the column and then display some kind of dialog with information I’m fetching with an API.

    Thanks!

    Jonatan

    1. Reggie

      Hi Jonatan,
      Yes of course there is a way to make it act as hyperlink, but you will use extensive coding for it to happen, and that is not what we want.
      As for a work around you may use a script that acts a shortcut to display the dialog.

      //Reggie

  95. Marcus

    Hi,
    In SmartOffice we have a script that is checking the validity of VAT numbers using a SOAP call ec.europa.eu (http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl), the plan was now to transform this script using Typescript and implementing it in H5.

    If the call is made using async true I get no changes in readyState or status, and of course then no response. If I instead use async false I get the below network error:

    Error: NetworkError: Failed to execute ‘send’ on ‘XMLHttpRequest’: Failed to load ‘http://ec.europa.eu/taxation_customs/vies/services/checkVatService’.

    The problem is that I do not seem to get it to work, I have tried different approaches with the latest being XMLHttpRequest but the readyState and status does not change when trying to call the external web service. Is it even possible to do in H5, I have been reading about problems with CORS and the availability to only call API’s on the same domain?

    I have used SoapUI to verify that the the information I am sending is working and is returning the response i require.

    Thanks / Marcus

    1. Karin Portillo Post author

      Hi,
      If you have a CORS issue that is shown by a log in the browser tools, so it’s not that in this case.
      You have to use async true. There has to be some issue with how you are making the call. Have you verified that the call is actually triggered? Use the Network tab in the browser or a tool like Fiddler to see that you are actually triggering the request. Then double check that you are using a post, that the data submitted is correct and so on. If you can run it in SoapUI you can compare the request/response data.

      1. Marcus

        Hi Karin,
        Thanks for your quick reply, it seems as I have a mixed content issue where we are trying to call a http service from an https site. You where in other words correct stating that the fault is in how the actual call is made, or made from in this case. I need to investigate this initial hurdle a bit more and see if there are any other on-line checks for this using https.
        /Marcus

  96. Nuno Monteiro

    Hello
    I am trying to run the H5SampleShowOnMap sample script that we can find on the H5 scripting manual, but I get this error:
    Refused to display ‘https://maps.google.com/maps?z=…&output=embed’ in a frame because it set ‘X-Frame-Options’ to ‘sameorigin’.
    Why is this happening? Does this have anything to do with “Cross domain calls are not allowed by default” issue that is mentioned in 3 H5 limitations? How can we solve this?
    Regards
    Nuno

      1. Nuno Monteiro

        Hi Karin.
        Thanks for your reply.
        But what about other sites? I am trying to make a script that shows tracking details from forwarding agents. Something like this (for testing purposes):
        var url = “http://www.logimat-delegaciones.net/SEGUIMIENTOEXPEDICIONES.ASPX?EMPRESA=RIOLOGISTIC&ANIO=2019&SERIE=01&NUMERO=00002676&REFERENCIA=2102763”
        ScriptUtil.Launch(url);

        However, this throughs the following error:
        jquery-1.10.2.min.js:5 Mixed Content: The page at ‘https://s65ff…. localScript=http://localhost:8080/MWS410B_Transportista.js’ was loaded over HTTPS, but requested an insecure resource ‘http://www.logimat-delegaciones.net/SEG…’. This request has been blocked; the content must be served over HTTPS.

        How can I solve this?
        Regards

  97. Jonatan Stenbacka

    Hi! How do I disable a drop-down in the best way?

    I’m trying to set the value and then making the drop-down read-only/disabled. I’ve tried doing it this way:

    this.controller.SetValue(“WRSTAT”, “10”);
    this.controller.GetElement(“WRSTAT”)[0].disabled = true;

    But then M3 doesn’t think that this field has a value, and since this field is mandatory the user gets stuck. If I remove the “disabled” part of the code, M3 detects the value. So SetValue works.

    Setting the “readonly” property as I would do with normal text fields does not seem to work for drop-downs. You can still pick a value in the drop-down.

    So is there a better way to disable a drop-down?

    // Jonatan

    1. Reggie

      Hi Jonatan,
      You may set it up like this.
      this.controller.SetValue(“WWQTTP”, “3”);
      this.controller.GetElement(“WWQTTP”).attr(“disabled”, “disabled”);

      //Reggie

      1. Jonatan Stenbacka

        Hi Reggie!

        Thank you for your answer, but this still gives me the same error actually. M3 complains about WRSTAT being empty, even though the value is set. If I remove the disable-code, the value is accepted.

        The value I’m trying to set is WRSTAT in CRS610/E, if that makes any difference.

        // Jonatan

      2. Marcus

        Hi Jonatan,
        How are you moving forward in the code from the panel that you are in, I had a similar problem where the actual value was ignored by M3 because the field was disabled. What I did was to set a value to the field, disabled it and then enabled the field the absolut last thing I did before sending the user on to the next panel. This only works though if you programmatically is sending the user forward, if not then the user will have the field enabled.
        /Marcus

    2. Reggie

      Hi,
      After digging deep into our code, it seems like H5 doesn’t want to include the fields to be changed that are readonly/disabled, that’s why it always goes back to its previous value.
      You may re-enable the field right after clicking next like Marcus’ said.
      //Reggie

      1. Jonatan Stenbacka

        Okay I finally managed to figure it out…

        As you said you have to enable the field right before the user is sent to the next panel. But as Marcus pointed out, it doesn’t work if the user presses “next”/ENTER, but only if you send the user through programmatically. Since I need to able to be able to navigate through the panels as usual, I found a way to get around that. I simply did it by catching the ENTER click, enable the field, and then invoke that same command programmatically.

        if (!this.statEnabled) {
        if (args.commandType == “KEY” && args.commandValue == “ENTER”) {
        this.controller.GetElement(“WRSTAT”)[0].disabled = false;
        this.statEnabled = true;
        args.cancel = true;

        setTimeout(() => {
        this.controller.PressKey(“ENTER”);
        }, 100);
        }
        }

  98. Kat

    Hi,
    Is there anyway can we Refresh-F5 , Close -F3 M3 screens example: OIS110 from H5 script?

    Thank You.

  99. Nuno Monteiro

    Hello
    I am trying to make a script that shows tracking details from forwarding agents, opening up another web page. Something like this (for testing purposes):
    var url = “http://www.logimat-delegaciones.net/SEGUIMIENTOEXPEDICIONES.ASPX?EMPRESA=RIOLOGISTIC&ANIO=2019&SERIE=01&NUMERO=00002676&REFERENCIA=2102763”
    ScriptUtil.Launch(url);

    However, this shows the following error:
    jquery-1.10.2.min.js:5 Mixed Content: The page at ‘https://s65ff…. localScript=http://localhost:8080/MWS410B_Transportista.js’ was loaded over HTTPS, but requested an insecure resource ‘http://www.logimat-delegaciones.net/SEG…’. This request has been blocked; the content must be served over HTTPS.

    How can I solve this?

    Thanks in advance
    Nuno

    1. Karin Portillo Post author

      Hi,
      It will not be possible to open a HTTP url within the H5 frame set. That is a security limitation. You have two options:
      1. Open with window.open(url,’_blank’);
      2. Check if that page can support HTTPS

  100. stéphane SCHAERER

    Hi,
    I try to re-use the example provided in H5SampleRegexValidator script, in OIS260 to validate that the “From Customer order number” (WFORNO ) and “To customer order number” (WTORNO) have same value before validating panel E. I though I can do this defining in the argument of the script, “regex” that both field has the same value:
    { “names”: [“WFORNO”], “regex”: ” WFORNO = WTORNO”, “message”: “From and To value shoul be the same” }
    Could someone help on this one?
    Thanks
    Stéphane

    1. Karin Portillo Post author

      Hi,
      That script only works for a regular expression match check. It takes the value for the WFORNO and applies the regular expression. It’s not possible to compare values at it is a standard regex and not a string that supports variable substitution.
      Eg. H5SampleRegexValidator is not for you scenario.

      You would need to create a new script that takes two arguments (field names) and verifies that their values are equal. It’s a simple script and you can use the sample as a starting point. Your script would only need the following input: { “names”: [“WFORNO”,”WTORNO”], “message”: “From and To value should be the same” } and then validate fields could look like this with only two values supported:

      private validateFields(): boolean {
      try {
      var validation= this.validations[0];
      if(!validation){
      return true;
      }
      let name1 = validation.names[0];
      let name2 = validation.names[1];

      let value1 = this.controller.GetValue(name1);
      let value2 = this.controller.GetValue(name2);
      // TODO check for null / undefined etc
      const result = value1!==value2;
      if(result){
      this.controller.ShowMessage(validation.message);
      return false;
      }
      return true;
      } catch (ex) {
      this.log.Error(“Failed to validate fields”, ex);

      // Return true if the script crashes to avoid getting stuck on a panel.
      return true;
      }
      }

  101. Nuno Monteiro

    Hi
    I am quite new to H5 scripting.
    For my development environment I’m using Visual Studio Code and Node.js
    So, I write my script in TypeScript, compile it using TSC command and then I get the corresponding JavaScript. I also use the StarWebServer cmd.
    Two questions:
    1. I get a lot of compiling errors, even though the script works fine in H5. So, I guess some “import” kind of stuff is missing in the compiler. How can I fix it?
    2. Is it possible to debug the script in the browser? How?
    Regards
    Nuno Monteiro

    1. Reggie

      Hi Nuno,
      After running the web server, could you please try to open the corresponding javascript in the browser and see if your webserver is working (ex. localhost:8085/H5SampleCancelRequest.js), also try to change the port for the server.
      1. The installer should import all what you need when running the webserver using node.js
      2. Yes it is possible to debug the script in the browser, attach it on your desired H5 environment and using the browsers developers tools.

      Regards,
      Reggie

  102. Jonatan Stenbacka

    Hi! Is it possible to manually filter a list in H5? I would like to remove some rows in a B-panel depending on some condition. Is this possible?

    Best regards,
    Jonatan

    1. Reginald Reyes

      Hi Jonatan,
      I would say that it is not possible for the rows, due to how the inforDataGrid works, the items on the rows are added by column by cell one by one.
      /Reggie

  103. yvonnickyou@lttd-consulting.com

    Hi,

    I use MIService in the following way:

    let myRequest = new MIRequest();
    myRequest.program = “MMS200MI”;
    myRequest.transaction = “GetItmWhsBasic”;
    myRequest.record[“WHLO”] = “D03”;
    //myRequest.record[“WHLO”] = this.controller.GetValue(‘VHWHLO’);
    myRequest.record[“ITNO”] = “101438”;
    //myRequest.record[“ITNO”] = this.controller.GetValue(‘WWPRNO’);
    var myPromise = MIService.Current.executeRequest(myRequest);
    Promise.all([myPromise]).then(response =>{
    }).catch(response =>{
    console.log(response.message);
    console.log(response.errorMessage);
    for(var item in response[0].items){
    value = item.WHSL;
    }
    });

    The script falls into error on the line:

    myRequest.record [“WHLO”] = “D03”;

    I do not understand why

    The error is :

    15:40:58,926] [ERROR] Failed to call Init function for script H5InitField Cannot set property ‘WHLO’ of undefined TypeError: Cannot set property ‘WHLO’ of undefined
    at H5InitField_WHSL.run (eval at (https://sd180001.xxxxxxx.local:19008/mne/controls/jquery/jquery-1.10.2.min.js?v=MTAuMy4xLjAuNDM5:4:4994), :91:33)
    at Function.H5InitField_WHSL.Init (eval at <anonymou

    Thanks in advance

    Best regards
    Yvonnick

    1. Tjalve Morken

      Hi Yvonnick,
      Looks like you have a blank between record and [“WHLO”]?
      (Try to remove the blank and see if that works)

      Kind Regards,
      Tjalve.

      1. Yvonnick

        Hi,

        Thanks for your response.

        I’m not a blank beetween record and [“WHLO”]
        Kind Regards,
        Yvonnick

  104. Yvonnick

    Hi Tjalve,

    Thanks for your response. I m not the blank between record.

    Kind Regards
    Yvonnick

    1. sanyukta2017

      Hi Yvonnick,

      I tried to do the below way and it works. Can you please try this way and check?

      var orno = this.controller.GetValue(“OAORNO”)
      var myRequest_1 = new MIRequest()
      myRequest_1.program = “OIS100MI”
      myRequest_1.transaction = “LstLine”
      myRequest_1.record = {
      CONO: CONO,
      ORNO: orno
      }
      myRequest_1.outputFields = [‘ORST’, ‘ITNO’, ‘PONR’]
      MIService.Current.executeRequest(myRequest_1).then(function (response) {
      _this.responseAvailable = true
      // Check the item type CFI4/CIF5 of the new item which is being added
      for (var _i = 0, _a = response.items; _i 33 && item.ORST != 99) {
      _this.showError(“Line cannot be added as the highest”, ” order line status is greater than 33.”)
      return
      }
      }

  105. SD

    Hi
    There is a standard M3 Add button in OIS101 to add line item. My script in OIS101 has a new button to perform some validations, I want to automatically click the standard Add button when validation is successfull. Can we do it from script to click the standard M3 Add button? Can you provide some example?

  106. sanyukta2017

    Hi SD, We can do it. When a user clicks on the validation button and when it is successful you can write a command to press enter.
    Something like this –
    _this.controller.PressKey(‘ENTER’);
    I have done a very similar thing in OIS101. But I did not create another button for validations! What if the user forgets to click on the validation button? What I did was –
    1) When a user clicks on the Add button, the script disconnects the action and performs the validations and when the validiation is successful I explicitly press the Enter key. Check out the example.
    var OIS101_Validations = (function () {
    function OIS101_Validate(args) {
    this.checked = false
    this.args = args.args
    this.controller = args.controller
    this.log = args.log

    }
    OIS101_Validate.Init = function (args) {
    return new OIS101_Validate(args).run()
    }
    OIS101_Validate.prototype.run = function () {
    this.attachEvents(this.controller)
    }

    OIS101_Validate.prototype.addLine = function () {
    var _this = this
    _this.checked = false

    //all your validations here!!
    //if successful then do the below otherwise throw an error msg
    setTimeout(function () {
    _this.controller.PressKey(_this.lastCommand)
    if (_this.lastCommand == ‘ENTER’) {
    _this.checked = true
    }
    }, 100)

    }
    OIS101_Validate.prototype.showWarning = function (header, message) {
    console.log(‘header’ + header)
    console.log(‘message’ + message)
    ConfirmDialog.ShowMessageDialog({
    dialogType: “Warning”,
    header: header,
    message: message
    })
    }
    OIS101_Validate.prototype.showError = function (header, message) {
    ConfirmDialog.ShowMessageDialog({
    dialogType: “Error”,
    header: header,
    message: message
    })
    }
    OIS101_Validate.prototype.attachEvents = function (controller) {
    var _this = this
    this.detachRequesting = controller.Requesting.On(function (e) {
    _this.onRequesting(e)
    })
    this.detachRequested = controller.Requested.On(function (e) {
    _this.onRequested(e)
    })
    }
    OIS101_Validate.prototype.detachEvents = function () {
    this.detachRequesting()
    this.detachRequested()
    }
    OIS101_Validate.prototype.onRequesting = function (args) {
    this.log.Info(“Command type: ” + args.commandType + “; Command value: ” + args.commandValue)
    console.log(‘this.checked is in main func’ + this.checked)
    if ((args.commandType == “KEY” && args.commandValue == “ENTER”) && !this.checked) {
    args.cancel = true
    this.lastCommand = args.commandValue
    this.addLine()
    }
    }
    OIS101_Validate.prototype.onRequested = function (args) {
    this.detachEvents()

    }
    return OIS101_Validate
    }())

    1. SD

      Thank you Sanyukta.. this is exactly what I was trying to do. I appreciate you response.

      Regards..//SD

    2. YS

      Hi Sanyukta,

      I have a similar case with you where i need to perform some validation on program OIS101 for ‘Change’ key.

      I have the similar logic as your code:

      OSI101.prototype.onRequesting = function (e) {
      // Validation on Change option.
      var self = this;
      if ((e.commandType === “LSTOPT” && e.commandValue === “2”) && !this.checked) {
      e.cancel = true;
      this.lastCommand = e.commandValue // 2
      this.validation();
      }

      OSI101.prototype.validation = function () {
      var self= this;
      self.checked = true;

      // validation here then
      setTimeout(() => { self.controller.PressKey(‘2’); }, 400);
      }

      My problem is the PressKey(‘2’) will navigate me back to OIS300 instead of navigating me to ‘Change’ panel (OIS101/E).

      Can I know why it didn’t bring me to the correct panel and instead to bring me backward to OIS300?

      Thanks in advance!

      1. sanyukta2017

        Hi,
        Press key can be used only for Enter or F3. For changing the mode try using this.controller.ListOption(“2”).Also, make sure you select the line before executing listoption. Because there is a possibility that OIS101/B has many lines and we need to let the system know which lines need to be changed.
        You will find an example of selecting the lines in H5 development guide.
        Thanks,
        San

  107. SD

    Hello

    I am trying to read all items in OIS101/H panel using Listcontrol but looks like I just cannot use for loop to read thru all items since lines are not selected. I am giving a button for users to click which will read each item from the list and after doing some validation will update the UOM in the subsequent text box next to it. My struggle is how to read the item from the OIS101/H panel list. Any help greatly appriciated.

    Thanks
    SD

    1. Shashank Malali

      Hi SD,
      Have you achieved this through a button.? Can you share the entire script.
      I am having the similiar requirement in OIS101/H panel.
      And I am new to H5 scripting

  108. TN

    Hello

    How do I read thru listcontrol all items listed in OIS101/H panel without selecting all rows? Can we read thru 1st column all items without highlighting or selecting the rows? I want to do some validation reading all items in column 1 on button click but not able to figure out how to read all items. Anyone have tried it before.

    Thanks
    TN

    1. sanyukta2017

      Hi SD/TN,
      I run a For loop to select the lines first (one by one) and then read it. Check out the below code if it makes sense.
      var ExtendedWeight = (function () {

      function ExtendedWeight(args) {
      this.checked = false;
      this.args = args.args;
      this.controller = args.controller;
      this.log = args.log;
      }
      ExtendedWeight.Init = function (args) {
      return new ExtendedWeight(args).run();
      };
      ExtendedWeight.prototype.run = function () {
      const list = this.controller.GetGrid();
      const customColumnNum = list.getColumns().length + 1;
      this.appendColumn(list, customColumnNum);
      this.populateData(list, customColumnNum);
      this.attachEvents(this.controller, list, customColumnNum);
      };
      ExtendedWeight.prototype.appendColumn = function (list, columnNum) {
      const columnId = “C” + columnNum;
      let columns = list.getColumns();
      let newColumn = { id: columnId, field: columnId, name: “Extended weight “, width: 100 };
      if (columns.length < columnNum) {
      columns.push(newColumn);
      }
      list.setColumns(columns);
      }
      ExtendedWeight.prototype.populateData = function (list, columnNum) {
      var _this = this;
      const columnId = "C" + columnNum;
      for (let i = 0; i {
      //Populate additional data on scroll
      if (e.commandType === “PAGE” && e.commandValue === “DOWN”) {
      this.populateData(list, columnNum);
      }
      else {
      this.detachEvents();
      }
      });
      }
      ExtendedWeight.prototype.detachEvents = function () {
      this.unsubscribeReqCompleted();
      }
      return ExtendedWeight;
      }());

    2. Reggie

      Hi SD/TN,

      Yes you may read all the items from the panel, since you have the controller after the button click, you need to navigate the items like this “controller.Response.Panel.List.Rows”, there you will see the loaded data on your screen with the corresponding row id and column id, take note that there will only be 33 lines “on load” of each list, you need to scroll down/page down on the list if you wish to load the next 33 lines.

      Regards,
      Reggie

      1. SD

        Thank you Reggie for the response, I tried as you suggested and was able to get it working.

        SD

    3. Shashank Malali

      Hi TN,
      Have you achieved this.? Can you share the script please.
      I am having the similiar requirement in OIS101/H panel.
      And I am new to H5 scripting

      1. Sidh Ambre

        Hi Shashank Sorry for delay in responding had some issues with my email account I am able to read the row element using the for loop but i am still having issues with displaying the response from the api in the 3rd column text for each row. The data is updated in the 3rd column text but I have to switch to another tab and come back to see it in the column text fields. Staying on OIS101/H panel the data is not visible but shows up after I click on another tab. Here is the code snippet /** * MIService utility used here is still in development. * H5 Script SDK sample. */ /** * Executes M3 API calls to retrieve UOM */ var HpanelUOMAdd = (function () { function HpanelUOMAdd(scriptArgs) {

        var debug = scriptArgs.debug; this.log = scriptArgs.log; var controller = scriptArgs.controller; var content = controller.GetContentElement(); var userContext = ScriptUtil.GetUserContext(); // var CCONO = userContext[“CONO”]; var CCONO = userContext.CurrentCompany; var DIVI = userContext[“DIVI”]; var DTFM = userContext[“DTFM”]; var USER = userContext[“USID”]; debugger; var cupa; //for ( var it = 0; it 0; itm++) { //for ( var itm = 0; itm 0) //_this.controller.Response.Panel.List.Rows[itm – 1].C3 = cupa;

        if(OHITNO != “”) {

        //if(itm != “0”) //_this.controller.Response.Panel.List.Rows[itm – 1].C3 = cupa; var autp = “1”; var dxit = “1”; var itm2 = “0”; cupa= “”;

        if(OHORTP == “OMS” || OHORTP === “OMS”) OHCUNO = “000”+OHCUNO.substring(0,2); _this.log.Info(“OHCUNO: ” +OHCUNO); _this.log.Info(“OHWHLO: ” +OHWHLO); _this.log.Info(“OHITNO: ” +OHITNO); _this.log.Info(“OAORTP: ” +OHORTP);

        //MMS015 var myRequest2 = new MIRequest(); myRequest2.program = “MDBREADMI”; myRequest2.transaction = “SelMITAUN00”; myRequest2.outputFields = [“AUS2,ALUN”]; myRequest2.record = { ITNO: OHITNO,AUTP : autp }; MIService.Current.executeRequest(myRequest2).then(function (response1) { for (var _k = 0, _a = response1.items; _k < _a.length; _k++) { var item2 = _a[_k]; if(item2.AUS2.trim() === "1" || item2.AUS2 == "1") { cupa = item2.ALUN; _this.log.Info("CUPA MMS015:"+cupa); _this.log.Info("ITNO MMS015:"+OHITNO); _this.controller.Response.Panel.List.Rows[itm2].C3 = cupa; _this.log.Info("ITM MMS015:"+itm2); itm2++; _this.log.Info("ITM MMS015 plus:"+itm2); } } }).catch(function (response1) { //MPACIT10 var myRequest3 = new MIRequest(); myRequest3.program = "MDBREADMI"; myRequest3.transaction = "GetMPACIT10"; myRequest3.outputFields = ["CUPA"]; myRequest3.record = { WHLO:OHWHLO,DXIT: dxit,PACT: vPACT,ITNO: OHITNO}; MIService.Current.executeRequest(myRequest3).then(function (response2) { for (var _l = 0, _a = response2.items; _l < _a.length; _l++) { var item3 = _a[_l]; cupa = item3.CUPA; _this.log.Info("CUPA WITHOUT CUST:"+cupa); //_this.controller.Response.Panel.List.Rows[itm].C3 = item3.CUPA; _this.controller.Response.Panel.List.Rows[itm2].C3 = cupa; itm2++;

        }

        }).catch(function (response2) { debugger; //MPACIT00 //this.controller.Response.Panel.List.Rows[itm].C3 = "EE"; var myRequest1 = new MIRequest(); myRequest1.program = "MDBREADMI"; myRequest1.transaction = "GetMPACIT10_1"; myRequest1.outputFields = ["CUPA"]; myRequest1.record = { WHLO:OHWHLO,DXIT: dxit,PACT: vPACT,ITNO: OHITNO,CUNO: OHCUNO }; MIService.Current.executeRequest(myRequest1).then(function (response) { for (var _j = 0, _a = response.items; _j < _a.length; _j++) { var item1 = _a[_j]; cupa = item1.CUPA; _this.log.Info("cupa:"+cupa); //this.controller.SetValue("OBALUN",cupa); _this.controller.Response.Panel.List.Rows[itm2].C3 = cupa; itm2++; // } }).catch(function (response) { console.error("Error in MDBREADMI GetMPACIT10_1 Api:" + response.errorMessage); _this.controller.Response.Panel.List.Rows[itm].C3 = cupa; debugger;

        //Handle errors here //_this.controller.PressKey("ENTER"); });

        //_this.controller.Response.Panel.List.Rows[itm].C3 = cupa; console.error("Error in MDBREADMI GetMPACIT10 Api:" + response2.errorMessage);

        });

        //Handle errors here // debugger; //console.error("Error in MDBREADMI SelMITAUN00 Api:" + response1.errorMessage); });

        //MMS015 //_this.controller.Response.Panel.List.Rows[itm].C3 = cupa;

        }

        }//end of main for loop

        };

        return HpanelUOMAdd; }()); //# sourceMappingURL=HpanelUOMAdd.js.map

        On Tue, May 26, 2020 at 3:42 AM Developing for Infor Smart Office wrote:

        > Shashank Malali commented: “Hi TN, Have you achieved this.? Can you share > the script please. I am having the similiar requirement in OIS101/H panel. > And I am new to H5 scripting” >

      2. Shashank Malali

        Hi Sidh,
        Thanks for your reply. I was able to move ahead. But is was just a demo script. After customer approval I will once again begin to develop the script. I have posted my script below in this blog. Its yet to be approved by customer before i go ahead and develop it.

  109. Avven

    Hi, Based on the script H5SampleIonApiService , created a h5 script in that When i click a button i am trying to call IonApiService.Current.execute() to POST data as below, but getting error message as “Message Text is missing” , also tried JSON.Stringfy() but still its not working . what am i doing wrong?.

    $run.click(function () {
    var request = {
    url: IonApiService.Current.getBaseUrl() + “/” + _this.mingleEndpoint + “/SocialService.Svc/User/” + _this.userGUID + “/ColleagueFeeds/” + colleagueUserGUID,
    method: “POST”,
    data: {
    “MessageText”: “thisMessage”
    }
    };
    IonApiService.Current.execute(request).then(function (response) {
    if (!response.data.ErrorList) {

    }
    else {
    for (var _i = 0, _a = response.data.ErrorList; _i < _a.length; _i++) {
    var error = _a[_i];
    _this.log.Error(error.Message);
    }
    }
    }).catch(function (response) {
    _this.log.Error(response.message);
    });
    });

    1. Avven

      Hi , Quick update on IONApiservice after setting content-type in headers object it was successfully calling the mingle endpoint url from H5 script. Thank You.

      var request = {
      url: IonApiService.Current.getBaseUrl() + “/” + _this.mingleEndpoint + “/SocialService.Svc/User/” + “b8580b50-71d5-4cb8-bec8-5cc761f55f18” + “/Feeds”,
      method: ‘POST’,
      headers:{
      “content-type”: ‘application/json’
      },
      data: JSON.stringify({“MessageText”: “GH5Test1”})
      };

  110. Bas

    Hi,

    How to disable multiselect on M3H5 list (datagrid) and set it to be single row selection? I’ve try to do the following setting in my script however it doesn’t work. When user hold CTRL + select on row or Shift + click on row, with the following setting user still able to do multiselect (multiple selected rows are highlighted).

    ExampleCode.prototype.run = function () {
    var _this= this;
    var grid = this.controller.GetGrid();
    grid.setOptions({ multiSelect: false }); // to disable multiselect
    var handler = function handler(e, args) { _this.onSelectionChanged(e, args); };
    grid.onSelectedRowsChanged.subscribe(handler);
    this.attachEvents(this.controller);
    };

    What I want to achieve is :
    When user hold CTRL + select on row / Shift + click on row, there is always one row is being selected (this.controller.GetGrid().getSelectionModel().getSelectedRows() only show one item in its return array) and only one row (the selected row) being highlighted.

    Can anyone help on this? Thanks in advance.

    Best regards,
    Bas

    1. Karin Portillo Post author

      I’ve checked and it’s not possible to change the data grid to single select. But you can prevent navigation until all validation is passed. Just be sure to unregister the script when the user is allowed to pass through to the next panel.

      As part of the script you can unselect the rows with status 22, and in the dialog have the message that some of the rows are unselected, but if there are still rows that are OK in the selection they can press OK to continue.

      That is actually a better approach then changing the select behavior on the list. How to add validation and add a cancel event please compare to the script code for Smart Office https://smartofficeblog.com/2012/03/30/validating-m3-panels-using-jscript-and-mi-programs-before-a-request/. There might be some H5 script examples in the questions section for H5 as well.

      This question was also asked here https://community.inforxtreme.com/infor-developers/f/m3-development/14013/infor-m3h5—disable-multiselect-on-list-datagrid/39509

      Regards
      Karin

  111. Johanna Olsen

    Hi,

    Is it possible to use a script in a H5 mashup? If so, do you have any examples or any information about this somewhere?

    In our case we want to connect a script to a button in the mashup.

    /Johanna

  112. Shashank Malali

    Hi
    I have added the additional customized columns through H5 Script in OIS101/H panel SortingOrder 9. And I want to display the data in the additional columns corresponding to the item no which is first column as per the std m3 view. Trying to make it like a dashboard. And Std M3 already has some fields for that items like Qty, UOM. How can I read this fields and enter into my custom columns. For e.g There is a Lst column in standard and I want the same values to be displayed in Lst column which I created through Script and its last date uom etc. Mainly I want to do this on pressing Enter or Panel load or Refresh. Or is it necessary to have a button.?
    Below is my script and looking for logic in populate data function but not able to achieve.

    /**
    * H5 Script SDK sample.
    */
    /**
    * Appends a column to the current grid
    */
    var H5SampleCustomColumns = (function () {
    function H5SampleCustomColumns(scriptArgs) {
    this.controller = scriptArgs.controller;
    console.log(“Running1…”);
    }
    /**
    * Script initialization function.
    */
    H5SampleCustomColumns.Init = function (args) {
    new H5SampleCustomColumns(args).run();
    };
    H5SampleCustomColumns.prototype.run = function () {
    var list = this.controller.GetGrid();
    var customColumnNum = list.getColumns().length + 1;
    this.appendColumn(list, customColumnNum, “Lst”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Date”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Ord No”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Price”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “UOM”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “1st”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Date”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Ord No”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Price”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “UOM”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “2nd”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Date”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Ord No”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Price”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “UOM”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “3rd”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Date”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Ord No”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “Price”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;
    this.appendColumn(list, customColumnNum, “UOM”);
    this.populateData(list, customColumnNum);
    customColumnNum = customColumnNum + 1;

    this.attachEvents(this.controller, list, customColumnNum);
    };
    H5SampleCustomColumns.prototype.appendColumn = function (list, columnNum,columnName) {
    var columnId = “C” + columnNum;
    var columns = list.getColumns();
    var newColumn = {
    id: columnId,
    field: columnId,
    name: columnName,
    width: 100
    };
    if (columns.length < columnNum) {
    columns.push(newColumn);
    }
    list.setColumns(columns);
    };

    H5SampleCustomColumns.prototype.populateData = function (list, columnNum) {
    var columnId = "C" + columnNum;
    for (var i = 0; i < list.getData().getLength(); i++) {
    var newData = {};
    newData[columnId] = "" //+ i;
    newData["id_" + columnId] = "R" + (i + 1) + columnId;
    $.extend(list.getData().getItem(i), newData);
    console.log("Running…");
    }
    var columns = list.getColumns();
    list.setColumns(columns);
    };
    H5SampleCustomColumns.prototype.attachEvents = function (controller, list, columnNum) {
    var _this = this;
    this.unsubscribeReqCompleted = controller.RequestCompleted.On(function (e) {
    //Populate additional data on scroll
    if (e.commandType === "PAGE" && e.commandValue === "DOWN") {
    _this.populateData(list, columnNum);
    }
    else {
    _this.detachEvents();
    }
    });
    };
    H5SampleCustomColumns.prototype.detachEvents = function () {
    this.unsubscribeReqCompleted();
    };
    return H5SampleCustomColumns;
    }());

  113. JC

    Hi,

    I have a requirement from customer to check if date is on a weekend. How do check that on H5 typescript?

    Thanks.

    1. Karin Portillo Post author

      Oh, that is a tricky one. Probably you need to check public holidays as well. If you don’t need that check if the SoHo date picker has a method for that. Best would be if there is an API for that, like an M3 API or if you can create an M3 extension.

      1. Tjalve

        Maybe consider using CRS900MI (M3 System Calendar Interface).
        This will give you the day of week (so that you know that it is in a weekend).
        But in addition, you will also know if it is a bank day (to catch moving holidays), goods receiving day, production day etc.
        Try CRS900MI/LstSysCalendar with input FRDT and TODT (may be set to same date if you only need to check one date).

  114. YS

    Hi,

    I’ve follow the development guide and created a basic drillback customise script. This script has apply to MMS120/B.

    Problem:
    – When I press on the button, the Ming.le drillback API seem not getting invoke which I didn’t get navigate to CRS610/E, instead I’m still staying on MMS120/B.
    – ** I’m able to see the log message in browser console and I’ve use program MTS043/A to test the bookmark parameters

    Why the drillback API didn’t get fire (doesn’t work)?


    var DrillbackSample = (function () {
    function DrillbackSample(scriptArgs) {
    this.controller = scriptArgs.controller;
    this.args = scriptArgs.args;
    }
    DrillbackSample.Init = function (args) {
    new DrillbackSample(args).run();
    }
    DrillbackSample.prototype.run = function () {
    this.addButton();
    }
    DrillbackSample.prototype.addButton = function () {
    let self = this;
    let buttonElement = new ButtonElement();
    buttonElement.Name = 'btnBookmark';
    buttonElement.Value = "Shortcut"; // name of button
    buttonElement.Position = new PositionElement();
    buttonElement.Position.Top = 4;
    buttonElement.Position.Left = 52;
    buttonElement.Position.Width = 1;
    buttonElement.Position.Height = 20;
    let contentElement = this.controller.GetContentElement();
    let button = contentElement.AddElement(buttonElement);
    ScriptUtil.AddEventHandler(button, 'click', function (event) {
    self.invokeDrillback();
    });
    }
    DrillbackSample.prototype.invokeDrillback = function () {
    const drillback = `?LogicalId=lid://infor.m3.1&AccountingEntity=900_100&ViewId=Program=CRS610;TableName=OCUSMA;Option=5;Panel=E;KeyNames=OKCONO,OKCUNO&ID1=100000`;
    //Fire the drillback message using the Infor Ming.le CE JavaScript API
    infor.companyon.client.sendPrepareDrillbackMessage(drillback);
    console.log('click')
    }
    return DrillbackSample;
    }());

    Thank you.

  115. Shashank Malali

    Hi All,
    Currently in OIS061 we have sorting based on Item number and Start Date combination (Both fields part of the sub file) in B panel subfile, based on the index used in the view defination indicators. And OIS061 has only Sorting order no views.
    I have a requirement from Customer where they want Sorting based only on start date in the Subfile. Along with this I also need to add two more custom fields in subfile but all should be sorted on start date. Is this possible through H5 script or anybody worked on this kind of requirements?

      1. Shashank Malali

        Hi Karin,
        Thank you for the information. Yes I only asked this same question on Infor community forum.

  116. Maxime R.

    Greetings,
    A script has been installed on PPS250/E and its launching an automation to PMS020/E when ENTER is being pressed (PO line tied to MO). The problem is there may be several warning messages from the M3BE (purchase order line already in status 35, PO line tied to reference order…) before M3 validates the screen with the entered data (confirmed quantity + confirmed date)… resulting in several PMS020/E being launched by the automation. Question is : can we monitor such warning messages to launch only once the automation ? I don’t think this is doable but i ask in case. Thank you.

  117. Shashank Malali

    Hi,
    I have added columns in the list view/ sub file through H5 script. One of the column fields is the Qty of each item in last six months. I want to highlight the field added with a color or entire record with a color of the particular row.column which has a sum (qty) greater than 100
    Is this color highlight possible through H5 script the way we use for M3 fields through personalization ?

    1. Reggie

      Hi Shashank,
      Since the custom columns are not part of the list coming from BE, it is not possible to add personalizations to it.
      Regards,
      Reggie

      1. Shashank Malali

        Hi Reggie,
        Thanks for your reply. I was looking for the possibility of applying css to the custom field added by H5 script.
        I have conveyed this to customer that its not possible. Thanks again

      2. Shashank Malali

        Hi Reggie,
        There is a possibility to highlight the values with a color through H5 script.
        Here is the code which I got help from Community.infor.com for my question there.

        1554226

        Hi,
        I would say thank you very much. The code you shared above worked.
        I have modified your code as follows while adding my eighth column
        //Create eighth column header
        var columnId8 = “C” + (columnNum + 7);
        this.columnAppended = true;
        var columns8 = list.getColumns();
        //Create a custom formatter
        function MyCustomFormatter(row,cell,value)
        {
        console.log(row);
        console.log(cell);
        console.log(value);
        var color = “black” ;
        if (parseFloat(value)> 100){
        color = “red”;}
        var html = “” + value + “”;

        return html;

        }
        var newColumn8 = {
        id: columnId8,
        field: columnId8,
        name: “Last six months quantity”,
        width: 100,
        formatter: MyCustomFormatter //set the formatter to be used

        };
        if (columns.length < (columnNum + 7)) {
        columns.push(newColumn8);
        }
        //add the eighth column header
        list.setColumns(columns);
        It highlights the value according to my condition greater than 100 and it also highlights the entire column values as below.

      3. Reggie

        Hi Shashank,
        I thought you will want to use the H5 personalization to color the customized columns, using that is not possible since the customized columns are not being read or is not part of the entire list coming from BE, but you may always use a custom code formatter to add color to any elements/columns you want, because you have a total control of the script.
        Regards,
        Reggie

  118. Shashank Malali

    Hi Reggie,
    Thank you very much. I have one more small issue can you help me please?

    I have added the button using one script as above in this smartofficeblog. I have also used mforms automation . Everything works fine. But the button is not visible for very first session of the day when I start.
    I need to refresh the screen of OIS101/H where this script is added. And after the first refresh for all other sessions my button appears. Can you guide me please what may be the issue.
    Actually I have two scripts in OIS101/H one without button and second with Button. Is this causing any issue just because I have two scripts in one program?

    1. Shashank Malali

      Hi Reggie,
      Please ignore my above comment. I have changed the position of the button and its working fine.

  119. Nusran Saleem

    Hi

    We have requirement to develop an H5 Script for the OIS200 program. My requirement is when user enters alias number in OIS200 item number column, I need to call MMS025 API and retrieve relevant item number.
    I was able to retrieve all the information and replace the relevant item number in Item number cell, but when I set the value item number cell doesn’t change till click on inside the cell. Below is my code sample.

    private ValidateAndUpdateData(index: number) {
    const list = this.controller.GetGrid();
    let myCompany = ScriptUtil.GetUserContext(“CurrentCompany”);
    let popn: string = list.getData().getItem(index).C1;

    if (popn != “”) {

    const program = “MMS025MI”;
    const transaction = “GetItem”;
    //const record = { CONO: myCompany, ALWT: “02”, POPN: popn, ALWQ: “GTIN” };
    const record = { CONO: myCompany, ALWT: “02”, POPN: popn, ALWQ: “DU14” };
    const outputFields = [“POPN”, “ITNO”];

    MIService.Current.execute(program, transaction, record, outputFields).then(
    (response: IMIResponse) => {
    //Read results here
    let POPN: string = response.items[0].POPN;
    let ITNO: string = response.items[0].ITNO;

    list.getData().getItem(index).C1 = ITNO;

    I have a few questions,
    1). How can I set the value to editable cells?
    2). Can refresh the entire grid to overcome this issue?
    3). Can anyone help us to register a cell click event?
    Anyone has any idea about these questions please help us.

    Thank you

    1. Reggie

      Hi Nusran,

      Unfortunately the editable cells of H5s Grid has limitations when it comes to adding values, and adding the values directly to the cell data will not work, however there is one workaround that you may do to actually change the values inside the cells.

      First is to subscribe an on requesting listener to interrupt the post data (example inside the H5 Scripting document) before it applies, then you may add your M3 Api inside your listener function to fetch your data in MMS025MI.

      Then since you have full control of the instance controller, there is an object name “editedCells” inside it, that is the exact object that has the exact Row/Column index for the current edited cells right after you press keyboard “Enter”, then you may change the value.

      I hope it helps.

      Regards,
      Reggie

      1. priyanthahet

        Hi Reggie,

        Could you please share sample code, how can I access editedCells in instance controller.

        Thank you
        Regards
        Priyantha

      2. Reggie

        Hi,
        It is like accessing the GetGrid() function in your script.
        ex.
        this.controller.editedCells

        *since it is an object you just need to access it like this.
        *you must capture it inside the OnRequesting listener, I think it is written in the H5 Scripting document and we also have it as a sample script named “H5SampleCancelRequest”

        public static Init(args: IScriptArgs): void {
        new H5SampleCancelRequest(args).run();
        }

        private run(): void {
        this.unsubscribeRequesting = this.controller.Requesting.On((e) => {
        this.onRequesting(e);
        });
        this.unsubscribeRequested = this.controller.Requested.On((e) => {
        this.onRequested(e);
        });
        this.unsubscribeReqCompleted = this.controller.RequestCompleted.On((e) => {
        this.onRequestCompleted(e);
        });
        }

        private onRequesting(args: CancelRequestEventArgs): void {
        this.log.Info(“onRequesting”);
        let _this = this;

        //Add the api here and capture the editedCells object here
        }

        Regards,
        Reggie

      3. priyanthahet

        Hi Reggie,

        I checked this code in run time. I added this code to Visual studio watch, it displays all edit cells. unfortunately, when I add some code typescript, it gives below error message.

        Error TS2339 (TS) Property ‘editedCells’ does not exist on type ‘IInstanceController’.

        I appreciate your advice.

      4. Reggie

        Hi priyanthahet,

        Yes it will have an error on TS file since it is really not a part of IInstanceController, it is only a part of H5 Client and it should not have an error if you attach the JS file of the script.

        Using the object name is just a workaround because of how the grid editable cells are made due to the data grids limitation.

        Regards,
        Reggie

  120. Reggie

    Hi Nusran,

    Unfortunately the editable cells of H5s Grid has limitations when it comes to adding values, and adding the values directly to the cell data will not work, however there is one workaround that you may do to actually change the values inside the cells.

    First is to subscribe an on requesting listener to interrupt the post data (example inside the H5 Scripting document) before it applies, then you may add your M3 Api inside your listener function to fetch your data in MMS025MI.

    Then since you have full control of the instance controller, there is an object name “editedCells” inside it, that is the exact object that has the exact Row/Column index for the current edited cells right after you press keyboard “Enter”, then you may change the value.

    I hope it helps.

    Regards,
    Reggie

    1. Nusran

      Hi Reggie,
      Thank you very much for your quick response.
      Appreciate, If you can share sample code for this.

      Thank you
      Nusran

      1. Reggie

        Hi Nusran,

        You may use the sample code inside H5SampleCancelRequest.ts.
        So right before it sends the post data, you need to provide the exact Row and Column and the value, in this case you need to use “onRequesting”.

        private run(): void {
        this.unsubscribeRequesting = this.controller.Requesting.On((e) => {
        this.onRequesting(e);
        });
        }

        private onRequesting(args: CancelRequestEventArgs): void {
        this.log.Info(“onRequesting”);
        this.controller.editedCells = {R1C3: “TESTING”}
        }

        Regards,
        Reggie

  121. Nusran

    Hi Reggie,

    Thank you very much for the quick response,
    Appreciate it if can you share sample code for this

  122. mayuran05

    Hi,

    I am using IonApiService class to call an ION Api from H5 script. But I couldn’t call an ION REST API with POST method where I need to the pass the data as a JSON object to the API.

    this is the sample code I have implemented

    const request: IonApiRequest =
    {
    url: this.IONAPI,
    method: “POST”,
    record:
    {
    logicalId : “lid://infor.m3.m3”
    },
    data:
    {
    “workflowName”: “Test”,
    “instanceName”: “Test”,
    “inputVariables”: [
    {
    “name”: “ITGR”,
    “dataType”: “STRING”,
    “value”: “123”
    }
    ],
    “inputStructures”: []
    },
    headers:
    {
    contentType:”application/json”
    }

    };

    IonApiService.Current.execute(request).then((response: IonApiResponse) =>
    {
    console.log(“myscript: success callback”)},
    function(err){
    console.log(“myscript: there was an http error”);
    })

    But when executing, we are getting the error as “Failed to load resource. the server responds with a status 415”. So when when we checked the network option in the developers tool, we found that the default header content-type ( which is application /x-www-form-urlencoded) is not getting overridden by the header content-type (application/json) that I am passing to the API.
    Can you please advise on this please?

    Thank you

    Regards
    Mayuran

    1. Reggie

      Hi mayuran05,

      Could you please try this header.

      headers:{
      “content-type”: ‘application/json’
      },

      Regards,
      Reggie

  123. anirudhmahajanAnirudh

    Hi,
    I want to call the UPS address validation api from an H5 script and display the response that would be multiple lines in a popup box for the user to select the correct address from, Can anyone help me with the sample code,if its possible to do via H5 Scripting.

    Thanks.

  124. anirudhmahajan

    Hi,
    I want to call the UPS address validation api from an H5 script and display the response that would be multiple lines in a popup box for the user to select the correct address from, Can anyone help me with the sample code,if its possible to do via H5 Scripting.

    Thanks.

    1. Karin Portillo Post author

      Hi,
      Assuming UPS allow cors request to their API from a browser and the endpoint is public and without having to pass credentials it’s possible. I don’t have an example but perhaps readers of this blog has.

  125. Avven

    Hi Karin/Reggie,

    In multi-tenant for H5 Scripts , do we need to Include CSRF token when we make an M3 api call using MIService.Current.executeRequest()? If yes, could you please advise how we need to implement it? .

    Thank you,
    Regards,
    Avven.

    1. Reggie

      Hi Avven,
      MIService handles the csrf token, the execute request scripting usage does not need any changes.
      Regards,
      Reggie

  126. Avven

    Hi, We have a requirement that in OIS101/H panel to populate the ALUN editable sub-file grid field, i am able to populate the ALUN editable field with the value properly but when i click “Enter” on the screen then its not taking the value that are populated on the ALUN field unless we get the focus on it for every line. I see multiple post here on regarding OIS101/H , has anyone faced similar scenario? is there any way to update the sub file grid to point the latest value after adding the value to the editable cell for all the lines?.i use the following standard approach to populate the value,

    var newData = {};
    newData[ALUNId] = ALUN;
    newData[“id_” + columnALUNId] = “R” + (i + 1) + ALUNId;
    $.extend(list.getData().getItem(i), newData);
    var columns = list.getColumns();
    list.setColumns(columns);

    Thank you,

    Regards,
    Avven

  127. Ahmed Taha

    Can someone help me please? Is there anyone who developed H5 script creating new window including window properties and structure like grid, list view, columns and rows like what we used to do via Jscript
    Please provide me with a sample for this code in order to get the idea of the syntax

  128. HeikoM

    Hi, I am able to set up a Visual Studio (2017) environment which allows to develop, execute and debug TypeScript, as it is briefly described in the “Infor M3 H5 Development Guide”. I can also develop in Visual Studio CODE, but cannot debug, and their is no explicit hint in the manual; debugging is no problem when I develop H5 Mashups with Angular and Odin in VS CODE, so I think there is only a small piece of connection missing. Can you help?

    1. Reggie

      Hi Heiko,

      First you have to download the Debugger for Chrome extension inside VS Code, then create a “launch.json” file to configure the chrome debugger and save it inside the .vscode folder (in my case .vscode folder is inside my Samples folder).

      *Take note that this will only work when using the stand-alone version of H5 (Cloud or On-prem)

      launch.json file configuration example (attach)
      *if your using attach, you need to run first the exact URL of the stand alone version plus the script you want to use, then click the debug button on the side panel and run the “Attach Chrome”.
      It should say that the connection is successful on the bottom part of VS Code

      {
      “version”: “0.2.0”,
      “configurations”: [
      {
      “type”: “chrome”,
      “request”: “attach”,
      “name”: “Attach Chrome”,
      “url”: “https://m3devapp.m3cedev.awsdev.infor.com/mne?localScript=http://localhost:8085/H5SampleCancelRequest.js”,
      “port”: 9222,
      “sourceMaps”: true,
      “webRoot”: “${workspaceFolder}”
      }

      ]
      }

      Regards,
      Reggie

  129. Marcus

    Hi,
    I am looking for a way to capture an eventual warning message from BE that is displayed in the status bar and to have it displayed as a dialog window instead, in other words to override the user setting for this via a script.
    Is this possible to do?
    Thanks / Marcus

    1. Reggie

      Hi Marcus,
      I don’t think we currently have the support for this, when the default setting is set to display in status bar and override it using scripts to display in a dialog.
      Regards,
      Reggie

  130. HeikoM

    Hi,
    where can I found any documentation about the Infor components, i.e. inforMessageDialog?
    best regards
    Heiko

      1. HeikoM

        Hi,
        I tried to execute a drillback, but nothing happens. I try to launch panel PMS080/E with the following (decoded) drillback:

        lid://infor.m3.1&AccountingEntity=100_100&ViewId=Program=PMS080;TableName=MWOMAT;Option=2;Panel=E;&Keys=VMMFNO,ID1,VMPRNO,ID2,VMMSEQ,ID3,VMCONO,ID4,VMFACI,ID5&ID1=4201901980&ID2=86701-04&ID3=81&ID4=100&ID5=100

        The full encoded drillback, which is executed by the function as argument, is::
        ?LogicalId=lid://infor.m3.1&AccountingEntity=100_100&ViewId=Program=PMS080;TableName=MWOMAT;Option=2;Panel=E;Keys=VMMFNO%2CID1%2CVMPRNO%2CID2%2CVMMSEQ%2CID3%2CVMCONO%2CID4%2CVMFACI%2CID5&ID1=4201901980&ID2=86701-04&ID3=81&ID4=100&ID5=100

        Problem: The function does nothing. I can’t see anything in the Chrome developer console log.

        Can you help?

      2. Reggie

        Hi HeikoM,

        Are you using a script to perform a drillback to H5? Performing a drillback to H5 need to have certain mandatory parameters to work.

        example:
        “bookmark?program=MMS001&tablename=MITMAS&keys=MMCONO,880,MMITNO,7200000002 &option=2&panel=E&name=MMS001/E&LogicalId=lid://infor.m3.1”

        If it is a drillback issue from a bookmark, I think it is better to file a ticket about this so that it could be further investigated by the developers.

        Regards,
        Reggie

  131. HeikoM

    Hi Reggie, regarding the drillback problem – I got confused by the Script Development Guide which states that “drillback” is the way to execute a bookmark; but from this blog thread, I took the information that simply ScriptUtil.Launch(…) can be used. Going that way it is an easy task. Thank you!
    Best Regards
    Heiko

  132. Bhumika Lekurwale

    Hi,
    I have a requirement as below:
    When we press F4 on a textbox of M3 program, it prompts the browse window which displays list of records. I need to iterate through each of those records and highlight the record which met certain condition.
    I wanted to know how can we get the controller of Browse window on click of F4 so that the record from prompted window can be read. Can someone guide me how this can be accomplished using H5 scripting.

    1. Reggie

      Hi Bhumika,

      You may use the H5 scripting sample in H5SampleCancelRequest, I think you could use the on requested listener or on request complete listener.

      On script load, it will automatically attach the listener to the current controller of the program, and on browse “F4” you will receive the dialog controller and can now manipulate the data on the current dialog controller and set the rows to be selected/highlighted.

      Regards,
      Reggie

      Example:

      SampleTestScript.prototype.run = function () {
      var _this = this;
      this.unsubscribeReqCompleted = this.controller.RequestCompleted.On(function (e) {
      _this.onRequestCompleted(e);
      });
      };

      SampleTestScript.prototype.onRequestCompleted = function (args) {
      var _this = this;
      this.log.Info(“onRequestCompleted”);
      var cont = args.controller; //this is the controller of the dialog

      if (cont.IsDialog() && cont.CMDVAL == “F4” || (cont.CMDVAL == “DOWN” || cont.CMDVAL == “UP” && cont.CMDTP == “PAGE”)) {
      _this.IterationAndHighlighting(cont); //pass the dialog controller
      } else if (cont.CMDVAL == “F12”) { //on close dialog
      this.unsubscribeReqCompleted(); //unsubscribe requested complete
      }
      };

      SampleTestScript.prototype.IterationAndHighlighting = function (inst) {
      //Do your iteration here
      //get active grid of controller and set selected rows to highlight the rows depending on your condition
      inst.ActiveGrid.setSelectedRows([1]);
      };

      1. Bhumika Lekurwale

        Hi Reggie

        Thanks a lot for your response. I will try it out for sure. However, i already able to implement it by reading the F4 window based on div id and then looped through all the records one by one.

        Regards,
        Bhumika

  133. chalanakalpitha

    Hi,
    Can I know, how to import 3rd party library to h5 script?(Need to add an excel reader).

  134. sharad

    Hi,

    I have created my own custom dialog to add radio button in it as it was not possible to include radio button in ConfirmDialog.
    Can someone assist me on how can I get the user selected radio button value from custom dialog back to the Infor M3 program panel where this custom dialog has been added.

    Regards,
    Sharad

  135. Sharad

    Hi Karin,
    Thanks for your response. I have not used it ever. There are lot of things on that page you suggested, not sure what should be used exactly.

    Basically, i have added my own custom dialog in H5 scripting to show the radio button which is getting populated without any issue. I am just wandering how can I fetch the radio button value which user will select/check and bring it to display on Infor M3 program panel.

    Regards,
    Sharad

    1. Reggie

      Hi Sharad,

      I assume you have a button that confirms your choice, so before initializing your custom dialog, you should attach the controller in your dialog element as data (example dialogDiv.data(“cont”, this.controller) ), so whenever you click the button, the controller data is passed down in the event data on click of the button and you may use it to navigate the element in the current panel you wish to write the value.

      Regards,
      Reggie

      1. sharad

        Hi Reggie,
        I am wandering how can I implement the idea you suggested in below piece of code which is used to to implement custom dialog box. This code is getting executed on ENTER button on M3 program panel:

        $(“body”).append(” +
        ‘Converted Line Qty ‘+decimal.toFixed(2)+”+baseUnit+’
        Round Down ‘+Math.floor(decimal)+”+baseUnit+’=’+down1.toFixed(2)+”+altunit+’
        Round Up ‘+Math.ceil(decimal)+”+baseUnit+’=’+up1.toFixed(2)+”+altunit+”);

        //Invoke the dialog on it
        $(‘#dialog1’).inforMessageDialog({
        title: “M3”,
        dialogType: “General”,

        close: function (event, ui) {
        $(this).remove();
        },
        buttons: [{
        text: “Ok”,
        click: function () {
        // Do something…
        var ele = document.getElementsByName(‘r1’);
        //var SelectedValue;
        for(i = 0; i {

        $(“#dialog1”).inforDialog(“close”);
        }, isDefault: true
        }]
        });
        console.log(“Final selected value out of custom dialog: “+SelectedValue); //failed to work

        I have marked “failed to work ” things in above code. I am able to print radioBtn SelectedValue in the Console.Log but unable to assign it to the WBORQA field which is available on M3 program panel.
        Also i am not able to print that SelectedValue out of the custom dialog in console.log or unable to assign it to any other field available on M3 program panel.

      2. Sharad

        Hi Reggie,
        Sorry, my earlier comment cut some content hence adding it here again,
        I am wandering how can I implement the idea you suggested in below piece of code which is used to to implement custom dialog box. This code is getting executed on ENTER button on M3 program panel:

        $(“body”).append(‘
        ‘ +
        ‘Converted Line Qty
        ‘+decimal.toFixed(2)+”+baseUnit+’
        Round Down ‘+Math.floor(decimal)+’
        ‘+baseUnit+’=’+down1.toFixed(2)+’
        ‘+altunit+’
        Round Up ‘+Math.ceil(decimal)+”+baseUnit+’=
        ‘+up1.toFixed(2)+”+altunit+”);

        //Invoke the dialog on it
        $(‘#dialog1’).inforMessageDialog({
        title: “M3”,
        dialogType: “General”,
        close: function (event, ui) {
        $(this).remove();
        },
        buttons: [{
        text: “Ok”,
        click: function () {
        // Do something…
        var ele = document.getElementsByName(‘r1’);
        //var SelectedValue;
        for(i = 0; i {
        $(“#dialog1”).inforDialog(“close”);
        }, isDefault: true
        }]
        });
        console.log(“Final selected value out of custom dialog: “+SelectedValue); //failed to work

        I have marked “failed to work ” things in above code. I am able to print radioBtn SelectedValue in the Console.Log but unable to assign it to the WBORQA field which is available on M3 program panel.
        Also i am not able to print that SelectedValue out of the custom dialog in console.log or unable to assign it to any other field available on M3 program panel.

        Regards,
        Sharad

    2. Reggie

      Hi Sharad,

      Before invoking the dialog, you must set the data to the element.
      $(“#dialog1”).data(“cont”. this.controller);
      then initialize …. $(“#dialog1”).inforMessageDialog..

      After setting the data, when clicking Ok button set the function to:
      buttons: [{
      text: “Ok”,
      click: function() {
      //here you now have a control to the instance controller
      var dialogData = $(this).data();
      //then check/get the value of the radio button
      //and since you already have control to the instance controller, you may navigate through the host which is in dialogData.cont.ParentWindow, and set the value
      //dialogData.cont.ParentWindow.find(“#WBORQA”).val(“Insert value from radio button here”)
      $(this).inforDialog(“close”);
      },
      isDefault: true
      }
      ]
      });

      Regards,
      Reggie

      1. Sharad

        Hi Sharad,

        Based on the solution you provided, my script worked as expected.
        Thanks a lot:)

        Regards,
        Sharad

    1. Reggie

      Hi HeikoM,

      Currently Target is not implemented in H5 web mashups, but my colleague said that we could make a workaround on this just by editing the XAML form of the mashup. I think we need the business process/requirement to investigate this further and in order to do that, this needs to be filed as a ticket so we could help you more in fixing the forms for H5 mashups.

      Regards,
      Reggie

      1. HeikoM

        Hi Reggie,

        thank you; this issue was basically raised by a customer, who wants to create an application which he can use to confirm stock movements. His Smart Office version works perfect, it performs an “Update” API call in M3 and displays a confirmation message to the user if the transaction was executed (or an error message). It was no option for him to create a M3 H5 SDK app, which requires a totally different skillset. If there is no other option to achieve this goal in an Enterprise Mashup, I can ask the customer to create the incident.

        Best regards
        Heiko

  136. Bhumika Lekurwale

    Hi,
    Can someone assist me on below.
    I was thinking to use MForms automation to copy value from a different panel to the current one.
    Here both panels are of same program. Is it really possible with Mforms automation?

    Below is the syntax to call different program but how can we call specific panel here?
    var auto = new MFormsAutomation();
    auto.addStep(ActionType.Run, “OIS101”);

    Regards,
    Bhumika

    1. Karin Portillo Post author

      Hi,
      You should not use automation for this. With automation you would have to edit the panel sequence and then add returns to pass through. You should use a stateless bookmark to load the panel data for a specific panel. So start searching for how to run a bookmark.

  137. Priyanka

    Hi,

    I am relatively new to scripting and in the learning phase. My requirement is to call an API after the User clicks ‘Next’ button on panel. Among below two options, which would be a better approach to do so. Also appreciate if you could please share some code for it.

    1. Capture the onclick of the Next button using it’s div id or class and call the MI in that click event.

    2. To use the Requested, requesting methods to get access of Next button and API call

    Awaiting your response,

    Thanks,
    Priyanka

    1. Karin Portillo Post author

      Option 2. There are examples on the site, search for request for example. Perhaps Regie has some samples. Is it a fire and forget type of call? To add stuff on the button does not work if they just press enter so avoid that.

      1. Priyanka

        Thank you so Karin for your prompt response. I understand your point, will keep this mind. Will use the second approach.

    2. Reggie

      Hi Priyanka,
      Yes, it is better to use option 2, you may use on requesting, on requested or on request completed methods written in the document.

      Regards,
      Reggie

      Example from the document.

      H5SampleCancelRequest.prototype.run = function () {
      var _this_1 = this;
      this.unsubscribeRequesting = this.controller.Requesting.On(function (e) {
      _this_1.onRequesting(e);
      });
      this.unsubscribeRequested = this.controller.Requested.On(function (e) {
      _this_1.onRequested(e);
      });
      this.unsubscribeReqCompleted = this.controller.RequestCompleted.On(function (e) {
      _this_1.onRequestCompleted(e);
      });
      };
      H5SampleCancelRequest.prototype.onRequesting = function (args) {
      this.log.Info(“onRequesting”);
      var _this = this;
      if (args.commandType === “KEY” && args.commandValue === “ENTER”) {
      console.log(“CALL API here”)
      }
      };
      H5SampleCancelRequest.prototype.onRequested = function (args) {
      this.log.Info(“onRequested”);
      };
      H5SampleCancelRequest.prototype.onRequestCompleted = function (args) {
      this.log.Info(“onRequestCompleted”);
      this.unsubscribeRequested();
      this.unsubscribeRequesting();
      this.unsubscribeReqCompleted();
      };

  138. Sharad

    Hi,
    Using H5 scripting, I have created a custom textbox named “CONum” in a B panel.I am trying to fetch value of same the textbox inside onRequestCompleted method but it is failed. I have tried multiple ways like using ScriptUtil, this.controller etc but none of them worked.
    Can anyone suggest me in finding what went wrong in the code written below:

    this.controller.RequestCompleted.On(function (e) { this.onRequestCompleted(e); });

    onRequestCompleted = function (e){
    if (e.commandType === “KEY” && e.commandValue === “ENTER”) {
    console.log(“INSIDE ENTER”);
    var inputORNO=ScriptUtil.GetFieldValue(“CONum”, this.controller);
    var inORNO = this.controller.GetValue(“CONum”);
    }
    }

  139. Avven

    Hi, I have a requirement that to create a new related option under Related menu or new option under Action menu using H5 Script. Is it possible to create using H5 Script or is there any alternative solution?

    Thanks,
    Avven.

    1. Reggie

      Hi Avven,
      We haven’t tried doing that on our side since those menus are created based on what is received from the business engine side and H5’s core functionalities.

      We have this shortcut space where you can add a functionality for related option, link for any URL, links for document archive and sorting order, I don’t know if it will be sufficient for your requirement.

      If the shortcuts won’t help, you may create your custom set of dropdown list.

      Regards,
      Reggie

      1. Avven

        Hi Reggie,

        Thank you so much for replying. I think shortcut will be helpful approach for my requirement, I will try it out.

        Regards,
        Avven

  140. Johanna

    Hi!

    I looking for a solution to create a custom browse window (F4 prompt) where I will have a list of values based on an API call. In the browse window it should be possible to search and select a record and populate the field in the panel with the selected record from the list.

    I know it was possible in Smart Office, but is this possible to do via typescript in H5? If it is, do you have any example code of this or could give me a hint of what element to use?

    Thanks in advance
    Johanna

  141. Shashank Malali

    Hi,
    Can anybody tell me how can I do role based personalizations in M3 on -prem both in smart office and H5.
    In smart office if I open personalizations manager i see four sequences Global, Role, User and Program. same in H5.
    I want to add the roles under “Role” tab but I can’t see any option (button or tab) to add new role.
    Do I need any access?
    My H5 scripts with arguments same as smart office used as shortcuts have wiped out the arguments of smart office scripts (Used as shortcut) when I deployed the Shortcuts with the H5 script along with its personalization files.
    I did this for Global role which caused the issue.
    Our Customer is migrating on cloud. So they are currently in on-prem they want to give H5 to users for hands on but at the same time they want to keep smart office also active for the users

  142. Priyanka

    Hi,
    Can anybody tell me if we can use Session.Cache(key,value) across multiple programs in the same session?

  143. Priyanka

    In continuation to above question, my concern is that can we retrieve values stored in the first program (where we enter the values) on the last program in the flow using Session.Cache.

    Thanks in advance!

    1. Reggie

      Hi Priyanka,
      You mean the Session Storage? yes you may use it to share across the current session just create a unique key for it.

      Regards

  144. Johanna Olsen

    Hi,

    The new UI in Cloud that was available from January is according to KB 2164523 using the latest Infor Design System components.

    I have tested some scripts that worked in the old H5 UI but in the new UI they are no longer working as expected.

    How do I know how to rewrite/adjust these script to get them to work? Do you have any documentation?

    Thanks in advance
    Johanna

  145. Supun Jayarathne

    Hi,
    I have to implement some validation on focusin and focusout events for Grid cell’s editable input (Ex: “R1C6”) in H5 Script. I Need to know how could achieve this.

  146. Supun Jayarathne

    Hi,
    I have to implement some validation on focusin and focusout events for Grid cell’s editable input (Ex: “R1C6”) in H5 Script. I Need to know how could achieve this.

  147. Suraj

    Hi ,
    i have to implement checkbox in h5 scripting.
    I have used above Matt code of checbox but its not working.
    I My function is not callling.

    var $rbtnGroup = $(“” +
    “Option 1” +
    “Option 2” +
    “”);

    //$rbtnGroup.find(“inforCheckbox”).inforCheckbox();
    var contentElement = this.controller.GetContentElement();
    contentElement.Add($rbtnGroup);
    function selectOnlyThis(id) {
    for (var i = 1;i <= 4; i++)
    {
    document.getElementById(i).checked = false;
    }
    document.getElementById(id).checked = true;
    }

    }

    ERROR—VM12644:1 Uncaught ReferenceError: selectOnlyThis is not defined
    at HTMLInputElement.onclick (VM12638:1)

    Thanks,

    1. Karin Portillo Post author

      Hi,
      I think a lot of your code is missing because it’s not formatted in a code block for WordPress. My guess is that you need to create the radio button group as a JQuery element and then assign the function to the click method. You can search how to do that online, it’s not specific to H5.

  148. Sharad

    Hi,
    I have developed a H5 script on one of the Infor M3 program to add a Textbox and a button to perform action on the value entered in the same textbox.
    In the same program i have enabled an enterprise search. On running the enterprise search, my textbox and button added using H5 scripting gets disabled(Textbox becomes not editable).

    Can someone assist me on how can we allow script to run without having an any impact of an enterprise search.

    Regards,
    Sharad

    1. Reggie

      Hi Sharad,
      Would you mind sharing the code, this is the first I have heard this kind of issue, I would like to test it on my end.
      Thanks,
      Reggie

  149. Sharad

    Hi Reggie,

    Thanks a lot for your quick response.
    Just to give you quick idea, my script is not doing anything complex. Its simply used to add new textbox and a button. It is working as expected.
    Only the worry started when we activated Infor enterprise search on the same panel. On executing enterprise search, my textbox and button becomes un-editable(Meaning i can edit textbox and can not click on button). Then, to make to make them editable, i need to refresh panel again which reloads script.

    Basically what I want to understand is that how can we make H5 script work even after the enterprise search without refreshing the panel.
    Sorry but i don’t know how to paste screenshots here to show . Can I get your mail ID, i can share details there.

    Regards,
    Sharad

    1. Reggie

      Hi Sharad,
      You may copy the code code snippet and paste it here, I’ll just create a copy of that on my side.
      Regards,
      Reggie

  150. YS

    Hi,

    I would like to set an editable cell to be NOT editable. May someone assist me to achieve this?
    The grid option “editable” where will disabled the whole grid cell which doesn’t suit to me case.

    Thanks in advance!

    Best regards,
    YS

  151. Bhumika

    Hi,
    I have created a custom dialog box in one of my script, Dialog is getting prompted as expected.
    After returning from dialog box, I wanted to execute the statement this.controller.PressKey(“ENTER”);
    as shown in the script code given below but this statement is not getting executed.
    Instead, getting an error “Uncaught TypeError: Cannot read property ‘PressKey’ of undefined”.
    Can someone assist me to make this statement work. Below is the code:

    $("body").append('' +
    'Converted Line Qty '+Qty+''+bas_Unit+'
    Down Qty '+TotalVal+''+bas_Unit+'='+down1+''+unit+'
    Up Qty '+TotalVal+''+bas_Unit+'='+up1+''+unit+'');
    $("#dialog1").data("cont",this.controller);
    //Invoke the dialog on it
    $('#dialog1').inforMessageDialog({
    title: "M3",
    dialogType: "General",
    close: function (event, ui) {
    $(this).remove();
    },
    buttons: [{
    text: "Ok",
    click: function () {
    // Do something...
    debugger;
    var dialogData = $(this).data();
    var ele = document.getElementsByName('r1');
    for(i = 0;i {
    //this.openDialog2();
    $("#dialog1").inforDialog("close");
    }, isDefault: true
    }]
    });

    Quick assistance would be really appreciated.
    Regards,
    Bhumika

    1. Karin Portillo Post author

      this.controller is not in the scope when you try to call it so it’s undefined.
      $(“body”) seems strange to me as well.
      Declare a varaible for the controller and use that instead of “this” is a standard solution for when this is something else than what you expect.
      So as you add the dialog in the script that has the controller just add var m3Controller and make sure that you use that variable in the callback handler, it should be scoped on then. The code that you have is not enough to actually see what you are trying to do since it does not have the this.controller. mentioned anywhere.

      1. Bhumika

        Hi Karin,
        I am trying to add full code but it is getting cut automatically, not sure why is that. Anyways, again I am pasting the full code again here, hopefully that would work.

        $(“body”).append(” +
        ‘Converted Line Qty ‘+Qty+”+bas_Unit+’
        Down Qty ‘+TotalVal+”+bas_Unit+’=’+down1+”+unit+’
        Up Qty ‘+TotalVal+”+bas_Unit+’=’+up1+”+unit+”);

        $(“#dialog1”).data(“cont”,this.controller);

        //Invoke the dialog on it
        $(‘#dialog1’).inforMessageDialog({
        title: “M3”,
        dialogType: “General”,
        close: function (event, ui) {
        $(this).remove();
        },
        buttons: [{
        text: “Ok”,
        click: function () {
        // Do something…
        debugger;
        var dialogData = $(this).data();
        var ele = document.getElementsByName(‘r1’);
        for(i = 0;i {
        //this.openDialog2();
        $(“#dialog1”).inforDialog(“close”);
        }, isDefault: true
        }]
        });

  152. Bhumika

    Hi Karin,
    Thanks for your quick response.
    Again the code did not get added properly on the portal, so let me add here only the required things, I have added this.controller.PressKey(“ENTER”) right after the for loop.
    This for loop is inside the custom dialog box.

    buttons: [{
    text: “Ok”,
    click: function () {
    // Do something…
    debugger;
    var dialogData = $(this).data();
    var ele = document.getElementsByName(‘r1’);
    for(i = 0;i {
    //this.openDialog2();
    $(“#dialog1”).inforDialog(“close”);
    }, isDefault: true
    }]
    });

    1. Bhumika

      Hi Karin,
      Below is piece of code where has been added. This statement is added inside the custom dialog box.

      ScriptUtil.SetFieldValue(“WBORQA”,SelectedValue);
      $(this).inforDialog(“close”);
      this.controller.PressKey(“ENTER”);
      return;
      }
      }, {
      text: “Cancel”,
      click: () => {
      //this.openDialog2();
      $(“#dialog1”).inforDialog(“close”);
      }, isDefault: true
      }]
      });

  153. Sharad

    Hi,
    It is feasible to create a shortcut in Toolbox area for related options. But,
    can someone confirm if it is possible to create a shortcut in Toolbox area for Option like ‘Display(CTRL+5)’ which is not a related option.

    If possible then how it can be done.

    Regards,
    Sharad

  154. mayuran05

    Hi,
    I am updating a table from API call inside OnRequesting (Enter) method. But once the user press enter, there can be validation from M3 and it can throw warning message. Since the user have pressed Enter, my script is getting executed regardless of the warning msg thrown by M3. I want to stop executing the OnRquesting method in my script, if there is a warning message.

    Regards
    Mayuran

    1. Reggie

      Hi,
      I think you can use the OnRequested handler, since you need the validation first from H5, and if it goes well without the warning, push through with your API call.
      Regards,
      Reggie

      1. JC

        Hi,

        I’m having the same problem as well. I have an input box in panel e then I will validate in an API. When there is an error in the API a dialog box will be displayed, which is ok. But after pressing ok on the dialog box(without changing the value on the input field) then press enter again script was not able to catch the error.

        How can OnRequested be use if there is a dialog box?

        Thanks.

  155. Asaf Meir

    Can we have an autimatic migration tool? JScript from SO 2 H5 javascript…
    Or perhaps an advisor or any sort of help with it.
    Thank
    Cheers
    //Asaf

    1. Karin Portillo Post author

      Hi,
      No, as you can imagine a migration tool from one language to another would require too much investment and would not be realistic. It’s not just a matter of one language vs another – it’s the security model that is very different in a browser as well. You might not even be allowed to call endpoints that you can call in .Net.

  156. Asaf Meir

    I built and imported the js file with the administration tool as described but can’t the find my script when I’m trying to add a shortcut to it (on any program) – what Am I doing wrong

    1. Reggie

      Hi Asaf,
      Please try logging off first and then log on again, the script is being populated on log on.
      Regards,
      Reggie

  157. Bhumika

    Hi,
    I am trying to call Infor M3 IPS service from H5 scripting.
    Can someone assist me in knowing, how to use ION API service account in H5 scripting to call the .
    Here, ideally I wanted to execute XML SOAP request through H5 scripting.

    Endpoint for IPS service is https://mingle-ionapi.inforcloudsuite.com/Client_TST/M3/ips/service

    Your suggestion on using ‘ION API service account- oauth2 token in H5 scripting’ would be really appreciated.

    Thanks in advance!

    Regards,
    Bhumika

  158. Bhumika

    Hi,
    I am trying to call Infor M3 IPS service from H5 scripting.
    Can someone assist me in knowing, how to use ION API service account in H5 scripting to call the . Here, ideally I wanted to execute XML SOAP request through H5 scripting.
    Endpoint for IPS service is https://mingle-ionapi.inforcloudsuite.com/Client_TST/M3/ips/service

    Your suggestion on using ‘ION API service account- oauth2 token in H5 scripting’ would be really appreciated.

    Thanks in advance!

  159. Sharad

    Hi,
    I have added one of the script on OIS101/B panel, purpose of the script is to to hide an already existing standard button. The code to hide a button has been written in run method of the script.

    When I open OIS101 program once, it hides the button as expected. At the same time if I open another instance again then it fails to hide the button.
    Can I know what could be the reason for such behavior.

    Can’t we open 2 instances of the same program/panel at a time?

    Regards,
    Sharad

    1. Karin Portillo Post author

      Hi,
      This should be possible without any issues as long as the scrip is deployed.

      You need to investigate the code and debug or add logging to see what happens the second time.

  160. Sharad

    Hi Karin,
    Thanks for your immediate response.
    Below is the piece of code I do have in my H5 script,

    OIS101_B_OrderLine.prototype.run = function () {
    this.log.Info(“in run…..”);
    var _this = this;
    $(‘#WAD74C0’).hide();
    }

    I am trying to hide a standard button here, which is working fine when I run first instance of OIS101/B, while keeping this instance open if I open another instance of OIS101/B panel, control goes to the piece of code written above still it fails to hide the button.

    Not sure why it fails to hide button even if the script executes the code.
    Could you please suggest.

    Regards,
    Sharad

  161. JC

    Hi,

    Im trying to validate 3 custom fields in h5. I am using a script and validating it against MNS150MI. When field 1 is correct and field is invalid, it will validate the invalid field but when you press enter again it will eventually accept invalid value. How can can I aolve this?

    Thanks.

    .

    1. Reggie

      Hi JC,

      In this case on requesting listener is used to capture the “Enter” key and validate before proceeding, but since you were validating it using an MI call, the codes work asynchronously and if the custom field MI call does accept the invalid value (meaning no parsing errors), it will still be saved because custom field has a different process.

      If it doesn’t hurt your process flow, I suggest for a work-around, attach your script to the shortcuts panel, then on click of the shortcut you will first validate the fields and after validating, the script will manually trigger a press key event for enter.

      Regards,
      Reggie

Comments are closed.