{"id":32795,"date":"2022-10-11T16:09:57","date_gmt":"2022-10-11T10:39:57","guid":{"rendered":"https:\/\/www.inogic.com\/blog\/?p=32795"},"modified":"2022-10-17T11:57:05","modified_gmt":"2022-10-17T06:27:05","slug":"steps-to-use-onoutputchange-client-api-reference","status":"publish","type":"post","link":"https:\/\/www.inogic.com\/blog\/2022\/10\/steps-to-use-onoutputchange-client-api-reference\/","title":{"rendered":"Steps to use OnOutputChange (Client API reference)"},"content":{"rendered":"<p>Microsoft recently introduced us to a new set of event handlers, which can be used to register or deregister a function when an output parameter of a PCF control is changed. By using the OnOutputChange method, seamless communication between PCF control &amp; Client API can be established. It is quite interesting to know that this works with standard as well as a virtual component. More on a virtual component can be checked <a href=\"https:\/\/www.inogic.com\/blog\/2022\/04\/exclusive-sneak-peek-at-the-new-virtual-pcf-component\/\" target=\"_blank\" rel=\"noopener\">here<\/a>.<\/p>\n<p>Let\u2019s look at the event handlers that are introduced first. They are as follows \u2013<\/p>\n<ul>\n<li>AddOnOutputChange \u2013 This will add an event handler to the OutputChange event of the selected control. The syntax is as below \u2013<\/li>\n<\/ul>\n<pre class=\"lang:css gutter:true start:1\">var control = formContext.getControl(\"&lt;name&gt;\");\r\ncontrol.addOnOutputChange(myFunction);<\/pre>\n<ul>\n<li>RemoveOnOutputChange \u2013 This will remove the event handler from the OutputChange event of the selected control. The syntax is as below \u2013<\/li>\n<\/ul>\n<pre class=\"lang:css gutter:true start:1\">var control = formContext.getControl(\"&lt;name&gt;\");\r\ncontrol.removeOnOutputChange(myFunction);<\/pre>\n<ul>\n<li>GetOutputs \u2013 This will return all the event handlers registered on the output change event of the selected control. The syntax is as below \u2013<\/li>\n<\/ul>\n<pre class=\"lang:css gutter:true start:1\">var control = formContext.getControl(\"&lt;name&gt;\");\r\ncontrol.getOutputs();<\/pre>\n<p>Below is what the getOutputs() returns \u2013<\/p>\n<p><img decoding=\"async\" class=\"size-full wp-image-32798 aligncenter\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1Client-API-reference.jpeg\" alt=\"Client API reference\" width=\"386\" height=\"122\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1Client-API-reference.jpeg 386w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1Client-API-reference-300x95.jpeg 300w\" sizes=\"(max-width: 386px) 100vw, 386px\" \/><\/p>\n<p>A key thing to know here is, the execution context will be passed automatically to the event handler when output is changed in the PCF control to easily acquire the formContext.<\/p>\n<p>Let\u2019s quickly look at the demonstration of the same. For demonstration purposes, I\u2019m creating a PCF control for the <strong><em>firstname<\/em><\/strong> field\/column of the <strong>Contact<\/strong> entity\/table which will show a field-level notification if the first name consists of any numeric values.<\/p>\n<p>We\u2019ll follow the below steps to achieve the aforementioned \u2013<\/p>\n<p>1. Create a Virtual PCF component by using the below command \u2013<\/p>\n<p>pac pcf init &#8211;namespace &lt;namespace&gt; &#8211;name &lt;controlName&gt; &#8211;template field &#8211;framework react<\/p>\n<p>2. After the component is created, install npm packages using<\/p>\n<p>npm install.<\/p>\n<p>3. Add the properties like the below in ControlManifest.xml\u2013<\/p>\n<pre class=\"lang:css gutter:true start:1\">&lt;property name=\"textField\" display-name-key=\"Text Field\" description-key=\"Select Text Field which should be checked\" of-type=\"SingleLine.Text\" usage=\"bound\" required=\"true\" \/&gt;\r\n\r\n&lt;property name=\"isValidValue\" display-name-key=\"String Value validation result\" description-key=\"String Value validation result\" of-type=\"TwoOptions\" usage=\"output\"\/&gt;<\/pre>\n<p>4. Make changes to the index.ts file as per below. We are reading the value from the text field, and checking it against a regex which checks if the input string contains any numeric character. We will pass the Input Changed function as a callback function to our main component\u2019s props. And in the getOutputs, we will set the output parameters.<\/p>\n<pre class=\"lang:css gutter:true start:1\">public init(\r\n\r\ncontext: ComponentFramework.Context&lt;IInputs&gt;,\r\n\r\nnotifyOutputChanged: () =&gt; void,\r\n\r\nstate: ComponentFramework.Dictionary\r\n\r\n): void {\r\n\r\nthis.notifyOutputChanged = notifyOutputChanged;\r\n\r\nthis.currentFieldValue = context.parameters.textField.raw!;\r\n\r\nthis.isValidString = this.validateStringField(this.currentFieldValue);\r\n\r\n}\r\n\r\n\u00a0\r\n\r\n\/**\r\n\r\n* This function will check the string passed to it and will return if the string contains any numerical value\r\n\r\n* @param currentFieldValue value to be checked\r\n\r\n* @returns true or false based on regex checking\r\n\r\n*\/\r\n\r\nvalidateStringField(currentFieldValue: string): boolean {\r\n\r\nlet isValid:boolean = false;\r\n\r\nlet checker = new RegExp('^[A-z]*$');\r\n\r\ntry {\r\n\r\nisValid = checker.test(currentFieldValue);\r\n\r\n} catch (error) {\r\n\r\nconsole.log(error);\r\n\r\n}\r\n\r\nreturn isValid;\r\n\r\n}\r\n\r\n\u00a0\r\n\r\n\/**\r\n\r\n* Called when any value in the property bag has changed. This includes field values, data sets, global values such as container height and width, offline status, and control metadata values such as label, visible, etc.\r\n\r\n* @param context the entire property bag is available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions\r\n\r\n* @returns ReactElement root react element for the control\r\n\r\n*\/\r\n\r\npublic updateView(context: ComponentFramework.Context&lt;IInputs&gt;): React.ReactElement {\r\n\r\nconst props: IStringChekerProps = {\r\n\r\ndefaultValue: context.parameters.textField.raw!,\r\n\r\nonInputChanged: (event: React.FormEvent&lt;HTMLInputElement | HTMLTextAreaElement&gt;, newValue?: string | undefined) =&gt; {\r\n\r\nthis.currentFieldValue = newValue!;\r\n\r\nthis.isValidString = this.validateStringField(this.currentFieldValue);\r\n\r\nthis.notifyOutputChanged();\r\n\r\n}\r\n\r\n}\r\n\r\nreturn React.createElement(\r\n\r\nStringCheker, props\r\n\r\n);\r\n\r\n}\r\n\r\n\u00a0\r\n\r\n\/**\r\n\r\n* It is called by the framework prior to controlling receiving new data.\r\n\r\n* @returns an object based on nomenclature defined in the manifest, expecting object[s] for a property marked as \u201cbound\u201d or \u201coutput\u201d\r\n\r\n*\/\r\n\r\npublic getOutputs(): IOutputs {\r\n\r\nreturn {\r\n\r\ntextField:this.currentFieldValue,\r\n\r\nisValidValue : this.isValidString\r\n\r\n};\r\n\r\n}\r\n\r\n5. Our main components should look something like this \u2013<\/pre>\n<p>import * as React from &#8216;react&#8217;;<\/p>\n<pre class=\"lang:css gutter:true start:1\">import { Label, TextField } from '@fluentui\/react';\r\n\r\n\u00a0\r\n\r\nexport interface IStringChekerProps {\r\n\r\ndefaultValue?: string;\r\n\r\nonInputChanged: ((event: React.FormEvent&lt;HTMLInputElement | HTMLTextAreaElement&gt;, newValue?: string | undefined) =&gt; void) | undefined\r\n\r\n}\r\n\r\n\u00a0\r\n\r\nexport class StringCheker extends React.Component&lt;IStringChekerProps&gt; {\r\n\r\npublic render(): React.ReactNode {\r\n\r\nreturn (\r\n\r\n&lt;TextField\r\n\r\ndefaultValue={this.props.defaultValue}\r\n\r\nplaceholder='---'\r\n\r\nonChange={this.props.onInputChanged}\r\n\r\n\/&gt;\r\n\r\n)\r\n\r\n}\r\n\r\n}<\/pre>\n<ol start=\"6\">\n<li>We might also need to make changes to the <strong>d.ts<\/strong> file similar to those below to include the Input &amp; Output interfaces.<\/li>\n<\/ol>\n<pre class=\"lang:css gutter:true start:1\">\/*\r\n\r\n*This is auto-generated from the ControlManifest.Input.xml file\r\n\r\n*\/\r\n\r\n\u00a0\r\n\r\n\/\/ Define IInputs and IOutputs Type. They should match with ControlManifest.\r\n\r\nexport interface IInputs {\r\n\r\ntextField: ComponentFramework.PropertyTypes.StringProperty;\r\n\r\n}\r\n\r\nexport interface IOutputs {\r\n\r\ntextField?: string;\r\n\r\nisValidValue?: boolean;\r\n\r\n}<\/pre>\n<p>7. We are all set from the PCF side. Please go ahead and type in<\/p>\n<p>npm run build<\/p>\n<p>and once the build is completed, type in<\/p>\n<p>pac pcf push &#8211;publisher-prefix &lt;publisherName&gt;<\/p>\n<p>8. After the PCF is pushed successfully, we will first configure it and then move to the JavaScript part. The field configuration will look like the below \u2013<img decoding=\"async\" class=\"alignnone wp-image-32797\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/2Client-API-reference.jpeg\" alt=\"\" width=\"1169\" height=\"1423\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/2Client-API-reference.jpeg 599w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/2Client-API-reference-247x300.jpeg 247w\" sizes=\"(max-width: 1169px) 100vw, 1169px\" \/><\/p>\n<p>9. In JavaScript, we will add the event handler to the OnOutputChange event of firstname control. It should look something like the below \u2013<\/p>\n<pre class=\"lang:css gutter:true start:1\">namespace IKL {\r\n\r\nexport namespace PCF {\r\n\r\nexport class RibbonLibrary {\r\n\r\n\/**\r\n\r\n* This function will run onload of form and register validateName to the output change event of firstname\r\n\r\n* @param context\r\n\r\n*\/\r\n\r\nonLoad = (context:any):void =&gt; {\r\n\r\n\/\/get formContext\r\n\r\nlet formContext = context.getFormContext();\r\n\r\n\/\/get control\r\n\r\nvar control = formContext.getControl(\"firstname\");\r\n\r\n\/\/add validator function on output change event\r\n\r\ncontrol.addOnOutputChange(this.validateName);\r\n\r\n}\r\n\r\n\u00a0\r\n\r\n\/**\r\n\r\n* This function will check if the firstname has any other values than alphabets\r\n\r\n* @param OnOutputChangeContext\r\n\r\n*\/\r\n\r\nvalidateName = (OnOutputChangeContext?:any):void =&gt; {\r\n\r\n\/\/get the attribute\r\n\r\nlet attribute = OnOutputChangeContext.getEventSource();\r\n\r\n\/\/get formContext\r\n\r\nlet formContext = OnOutputChangeContext.getFormContext();\r\n\r\ntry {\r\n\r\n\/\/we've included a switch so that the same function can be used further for other fields\r\n\r\nswitch (attribute.getName()) {\r\n\r\ncase 'firstname':\r\n\r\nlet firstnameControl = formContext.getControl('firstname');\r\n\r\nlet firstnameControlOutput = firstnameControl.getOutputs();\r\n\r\nlet isValidFirstname = firstnameControlOutput[\"firstname.fieldControl.isValidValue\"].value;\r\n\r\n\/\/if the first name is invalid, show a notification\r\n\r\nif(!isValidFirstname){\r\n\r\nfirstnameControl.setNotification('Firstname should not contain digits','firstnameControlNotification');\r\n\r\n}\r\n\r\n\/\/else clear it\r\n\r\nelse {\r\n\r\nfirstnameControl.clearNotification('firstnameControlNotification');\r\n\r\n}\r\n\r\nbreak;\r\n\r\ndefault:\r\n\r\nbreak;\r\n\r\n}\r\n\r\n} catch (error) {\r\n\r\nconsole.log(error);\r\n\r\n}\r\n\r\n}\r\n\r\n}\r\n\r\n}\r\n\r\n}\r\n\r\nlet contactLib = new IKL.PCF.RibbonLibrary();<\/pre>\n<p>Note: From the above code we can see, where the method <strong><em>validateName<\/em><\/strong> is defined we have directly captured the PCF control\u2019s context as <strong><em>OnOutputChangeContext<\/em><\/strong>.<\/p>\n<p>10. Register the script on the load event of the contact form and we are done. It will look like the below in action \u2013<\/p>\n<p><img decoding=\"async\" class=\"alignnone wp-image-32796\" style=\"border: 1px solid #0a0a0a; padding: 1px; margin: 1px;\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/Demo.gif\" alt=\"\" width=\"825\" height=\"275\" \/><\/p>\n<h2><strong>Conclusion:<\/strong><\/h2>\n<p>This is how we can use the OnOutputChange event for a PCF control.<\/p>\n<p><a href=\"https:\/\/www.inogic.com\/product\/productivity-apps\/dynamics-365-crm-sharepoint-security-metadata-sync\" target=\"_blank\" rel=\"noopener\"><img decoding=\"async\" class=\"alignnone  wp-image-32801\" src=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1.jpg\" alt=\"\" width=\"832\" height=\"208\" srcset=\"https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1.jpg 800w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1-300x75.jpg 300w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1-768x192.jpg 768w, https:\/\/www.inogic.com\/blog\/wp-content\/uploads\/2022\/10\/1-660x165.jpg 660w\" sizes=\"(max-width: 832px) 100vw, 832px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Microsoft recently introduced us to a new set of event handlers, which can be used to register or deregister a function when an output parameter of a PCF control is changed. By using the OnOutputChange method, seamless communication between PCF control &amp; Client API can be established. It is quite interesting to know that this\u2026 <span class=\"read-more\"><a href=\"https:\/\/www.inogic.com\/blog\/2022\/10\/steps-to-use-onoutputchange-client-api-reference\/\">Read More &raquo;<\/a><\/span><\/p>\n","protected":false},"author":13,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[18,2361],"tags":[2633],"class_list":["post-32795","post","type-post","status-publish","format-standard","hentry","category-dynamics-365-v9-2","category-technical","tag-client-api-reference"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/32795","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/comments?post=32795"}],"version-history":[{"count":0,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/posts\/32795\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/media?parent=32795"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/categories?post=32795"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.inogic.com\/blog\/wp-json\/wp\/v2\/tags?post=32795"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}