{"id":1220,"date":"2014-04-21T10:21:09","date_gmt":"2014-04-21T04:51:09","guid":{"rendered":"http:\/\/ramkulkarni.com\/blog\/?p=1220"},"modified":"2014-04-21T10:21:09","modified_gmt":"2014-04-21T04:51:09","slug":"coldfusion-splendor-when-to-use-invokecfclientfunction","status":"publish","type":"post","link":"http:\/\/ramkulkarni.com\/blog\/coldfusion-splendor-when-to-use-invokecfclientfunction\/","title":{"rendered":"ColdFusion Splendor &#8211; When to use invokeCFClientFunction"},"content":{"rendered":"<p>I have seen some confusion when it comes to using invokeCFClientFunction. I have been asked this question a few times, more recently on LinkedIn, so I thought explaining it in a blog post might be a good idea.<\/p>\n<p>If you don&#8217;t know already, ColdFusion Splendor has added support for client side CFML (&lt;cfclient&gt;) and this code is translated to JavaScript. \u00a0You can call JavaScript functions from cfclient and vice versa.<\/p>\n<p>cfclient also makes calling asynchronous functions of PhoneGap easy by providing synchronous access to them. All device APIs are asynchronous in nature, but in cfclient block you call then as synchronous functions and ColdFusion translates them to asynchronous PhoneGap functions. All function starting with &#8216;cfclient.&#8217;, e.g. cfclient.camera.getPicture(), are asynchronous. In addition to device APIs, data access function, executeQuery and tag, cfquery, are also asynchronous in cfclient.<\/p>\n<p>When you call asynchronous functions in cfclient, ColdFusion takes care of chaining callback functions &#8211; any code following an\u00a0asynchronous\u00a0function goes in the success callback function. But if you call asynchronous cfclient function form JavaScript code block, then ColdFusion compiler does not touch it. Note that if a UDF in cfclient block calls any asynchronous function (e.g. cfquery or any device APIs) then that function also becomes asynchronous.<\/p>\n<p>Let&#8217;s see an example. In the following code, I have a UDF in cfclient block, createDatabase. It does not need any argument, but let&#8217;s say it takes one argument, arg1. This function calls queryExecute function, which is an asynchronous function &#8211; so createDatabase function also becomes asynchronous. If you call it from JavaScript and have some JS code to be executed\u00a0only after database is created, then calling createDatabase function directly from JavaScript is not going to work as expected &#8211;<!--more--><!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;cfclient&gt;<\/span>\n<span style=\"color: #007020;\">    &lt;cfscript&gt;<\/span>\n\t<span style=\"color: #996633;\">function<\/span> <span style=\"color: #0066bb; font-weight: bold;\">createDatabase<\/span>(<span style=\"color: #996633;\">arg1<\/span>)\n\t{\n\t\t<span style=\"color: #0066bb; font-weight: bold;\">console.log<\/span>(<span style=\"background-color: #fff0f0;\">\"arg1 = \"<\/span> <span style=\"color: #333333;\">+<\/span> <span style=\"color: #996633;\">arg1<\/span>);\n\t\t<span style=\"color: #996633;\">try<\/span>\n\t\t{\n\t\t\t<span style=\"color: #0066bb; font-weight: bold;\">queryExecute<\/span>(\n\t\t\t\t\t<span style=\"background-color: #fff0f0;\">\"create table if not exists expense (id integer primary key, <\/span>\n<span style=\"background-color: #fff0f0;\">\t\t\t\t\texpense_date integer, amount real, desc text, receipt_path text)\"<\/span>,\n\t\t\t\t[],\n\t\t\t\t{<span style=\"background-color: #fff0f0;\">\"datasource\"<\/span>:<span style=\"background-color: #fff0f0;\">\"tempDsn\"<\/span>});\n\t\t\t<span style=\"color: #0066bb; font-weight: bold;\">console.log<\/span>(<span style=\"background-color: #fff0f0;\">\"Database created\"<\/span>);\n\t\t}\n\t\t<span style=\"color: #0066bb; font-weight: bold;\">catch<\/span> (<span style=\"color: #996633;\">any<\/span> <span style=\"color: #996633;\">e<\/span>)\n\t\t{\n\t\t    <span style=\"color: #0066bb; font-weight: bold;\">console.log<\/span>(<span style=\"background-color: #fff0f0;\">\"Error : \"<\/span> <span style=\"color: #333333;\">+<\/span> <span style=\"color: #996633;\">e.message<\/span>);\n\t\t\t\t<span style=\"color: #996633;\">return<\/span> <span style=\"color: #996633;\">false<\/span>;\n\t\t\t}\n\t\t    <span style=\"color: #996633;\">return<\/span> <span style=\"color: #996633;\">true<\/span>;\n\t\t}\n\n<span style=\"color: #007020;\">    &lt;\/cfscript&gt;<\/span>\n<span style=\"color: #007700;\">&lt;\/cfclient&gt;<\/span>\n\n<span style=\"color: #007700;\">&lt;script &gt;<\/span>\n    ret <span style=\"color: #333333;\">=<\/span> createDatabase();\n    console.log(<span style=\"background-color: #fff0f0;\">\"After creating database. ret = \" + ret<\/span>);\n<span style=\"color: #007700;\">&lt;\/script&gt;<\/span>\n<\/pre>\n<\/div>\n<p>There is one console.log in createDatabase function immediately after queryExecute. createDatabase is called from a JavaScript block and after the function call, there is a console.log statement to print return value.<\/p>\n<p>If you execute this code in Chrome\/Safari, you will see following output &#8211;<\/p>\n<div class=\"console-message console-log-level\" style=\"color: #000000;\">\n<div class=\"console-group\" style=\"color: #000000;\">\n<div class=\"console-group-messages\">\n<h5 class=\"console-message console-log-level\"><span class=\"console-message-text source-code\">arg1 = arg1<br \/>\n<\/span><span style=\"font-size: 1em;\">After creating database. ret = undefined<br \/>\n<\/span><span style=\"font-size: 1em;\">Database created\u00a0<\/span><\/h5>\n<div class=\"console-message console-log-level\"><span style=\"font-size: 16px;\">This is not what you probably expected. You would want database to be created before returning to JavaScript code.<\/span><\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>To handle such scenario, where you want to call asynchronous functions declared in cfclient from JavaScript, Splendor provides a function called <strong>invokeCFClientFunction<\/strong>. The first argument to this function is name of a (cfclient) function to be called, followed by arguments to that function and the last argument is a callback function, which cfclient will call after executing the asynchronous function.<\/p>\n<p>We will replace JavaScript block above with following code &#8211;<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;script &gt;<\/span>\n    invokeCFClientFunction (<span style=\"background-color: #fff0f0;\">\"createDatabase\"<\/span>, <span style=\"background-color: #fff0f0;\">\"arg1\"<\/span>, <span style=\"color: #008800; font-weight: bold;\">function<\/span>(ret){\n\tconsole.log(<span style=\"background-color: #fff0f0;\">\"After creating database. ret = \"<\/span> <span style=\"color: #333333;\">+<\/span> ret);\n   });\n<span style=\"color: #007700;\">&lt;\/script&gt;<\/span>\n<\/pre>\n<\/div>\n<p>If you execute the code now, you will see following output &#8211;<\/p>\n<h5 class=\"console-message console-log-level\" style=\"color: #000000;\"><span class=\"console-message-text source-code\">arg1 = arg1<br \/>\n<\/span><span style=\"font-size: 1em;\">Database created<br \/>\n<\/span><span style=\"font-size: 1em;\">After creating database. ret = true<\/span><\/h5>\n<h5 class=\"console-message console-log-level\" style=\"color: #000000;\"><span style=\"font-size: 16px;\">This output is as\u00a0expected. cfclient function is completely executed and then subsequent\u00a0JavaScript code gets executed.<\/span><\/h5>\n<p>So use invokeCFClientFunction from JavaScript to call asynchronous cfclient functions. You do not need to use it if cfclient function is not asynchronous e.g. &#8211;<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #007700;\">&lt;cfclient&gt;<\/span>\n    function sayHello(name)\n    {\n        return \"Hello \" + name + \" !\";\n    }\n<span style=\"color: #007700;\">&lt;\/cfclient&gt;<\/span>\n\n<span style=\"color: #007700;\">&lt;script &gt;<\/span>\n    console.log(sayHello(<span style=\"background-color: #fff0f0;\">\"Ram\"<\/span>));\n    console.log(<span style=\"background-color: #fff0f0;\">\"After calling sayHello\"<\/span>);\n<span style=\"color: #007700;\">&lt;\/script&gt;<\/span>\n<\/pre>\n<\/div>\n<p>Note that ColdFusion decides if a UDF in cfclient is asynchronous after analyzing all the function calls from that UDF\u00a0recursively &#8211; so if UDF func1 in cfclient calls another UDF func2 and if func2 calls a device\/database API then func1 is also marked as asynchronous even if it does not directly call any device\/database function.<\/p>\n<p>There is a scenario where you don&#8217;t need to use invokeCFClientFunction from JavaScript to call asynchronous function in cfclient &#8211; when you just want to call-and-forget cfclient function i.e. the JavaScript code following the asynchronous function call does not depend on what that function does.<\/p>\n<p>-Ram Kulkarni<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I have seen some confusion when it comes to using invokeCFClientFunction. I have been asked this question a few times, more recently on LinkedIn, so I thought explaining it in a blog post might be a good idea. If you don&#8217;t know already, ColdFusion Splendor has added support for client side CFML (&lt;cfclient&gt;) and this &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/ramkulkarni.com\/blog\/coldfusion-splendor-when-to-use-invokecfclientfunction\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;ColdFusion Splendor &#8211; When to use invokeCFClientFunction&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"#ColdFusion Splendor - When to use invokeCFClientFunction http:\/\/wp.me\/p2g9O8-jG","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[32,20,78,1],"tags":[85,94,89,102],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/p2g9O8-jG","jetpack-related-posts":[],"_links":{"self":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1220"}],"collection":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/comments?post=1220"}],"version-history":[{"count":0,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/posts\/1220\/revisions"}],"wp:attachment":[{"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/media?parent=1220"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/categories?post=1220"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/ramkulkarni.com\/blog\/wp-json\/wp\/v2\/tags?post=1220"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}