{"id":3222,"date":"2025-09-04T17:07:33","date_gmt":"2025-09-04T22:07:33","guid":{"rendered":"https:\/\/xlinesoft.com\/blog\/?p=3222"},"modified":"2025-09-04T17:07:33","modified_gmt":"2025-09-04T22:07:33","slug":"moving-logic-from-javascript-to-the-database","status":"publish","type":"post","link":"https:\/\/xlinesoft.com\/blog\/2025\/09\/04\/moving-logic-from-javascript-to-the-database\/","title":{"rendered":"Moving logic from Javascript to the database"},"content":{"rendered":"<p>In this article we will discuss how to minimize the amount of code that handles Javascript on Add\/Edit pages. Making your code data-driven will help you easily manage forms with a huge numbers of fields. We will be taking care of functionality like showing\/hiding fields, making fields readonly, required, disabled etc. <\/p>\n<p>This approach will involve the following steps<br \/>\n1. Creating and populating database tables to store triggers ( when to apply the logic ) and actions ( what happens when trigger goes off )<br \/>\n2. Server-side PHP and C# code that passes this data to Javascript<br \/>\n3. Javascript code itself that listens to &#8220;change&#8221; event and implements the logic defined in the database.<\/p>\n<p><a href=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-600x400.png\" alt=\"\" width=\"600\" height=\"400\" class=\"alignnone size-medium wp-image-3233\" srcset=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-600x400.png 600w, https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-1024x683.png 1024w, https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9-768x512.png 768w, https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/f4e4f71c-f4d8-465c-8a1c-67dbe4d205b9.png 1536w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><br \/>\n<!--more--><\/p>\n<h3>Database tables<\/h3>\n<p>Triggers table. The structure is fairly simple. You can see that we store table name, page type, field name and what event we are listening to. In this article we will only show how to implement the most common &#8220;change&#8221; event as it covers 95% of required functionality. <\/p>\n<p><a href=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/triggers.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/triggers-600x104.png\" alt=\"\" width=\"600\" height=\"104\" class=\"alignnone size-medium wp-image-3226\" srcset=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/triggers-600x104.png 600w, https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/triggers.png 632w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>Actions table is a details one while triggers is a master. They are linked by trigger_id field. This table knows what condition to check and what action to perform. Lets take a look at the first row and try to decipher it.<\/p>\n<p>The action is tied to trigger #1 ( change event of Country field on the Edit page of customers table). The condition is equal and the condition_value is &#8216;USA&#8217;. Which means that when Country field equals &#8216;USA&#8217; we should proceed with our action. And the action itself is showing of the Region field. <\/p>\n<p><a href=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/actions.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/actions-600x269.png\" alt=\"\" width=\"600\" height=\"269\" class=\"alignnone size-medium wp-image-3225\" srcset=\"https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/actions-600x269.png 600w, https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/actions-768x345.png 768w, https:\/\/xlinesoft.com\/blog\/wp-content\/uploads\/2025\/09\/actions.png 789w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/a><\/p>\n<p>And here is the SQL script that will create both tables for you with sample data.<\/p>\n<div class=\"my-syntax-highlighter\">\n<pre><textarea id=\"mshighlighter\" class=\"mshighlighter\" language=\"sql\" name=\"mshighlighter\" >\r\nCREATE TABLE IF NOT EXISTS `actions` (\r\n  `id` int NOT NULL AUTO_INCREMENT,\r\n  `condition` varchar(250) DEFAULT NULL,\r\n  `target` varchar(250) DEFAULT NULL,\r\n  `action` varchar(250) DEFAULT NULL,\r\n  `condition_value` varchar(250) DEFAULT NULL,\r\n  `trigger_id` int DEFAULT NULL,\r\n  KEY `Index 1` (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;\r\n\r\nINSERT INTO `actions` (`id`, `condition`, `target`, `action`, `condition_value`, `trigger_id`) VALUES\r\n\t(1, 'equals', 'Region', 'show', 'USA', 1),\r\n\t(2, 'empty', 'ContactTitle', 'hide', NULL, 2),\r\n\t(3, 'notepmty', 'ContactTitle', 'readonly', NULL, 2),\r\n\t(4, 'notempty', 'ContactTitle', 'show', NULL, 2),\r\n\t(5, 'notequals', 'Region', 'hide', 'USA', 1),\r\n\t(6, 'notempty', 'Fax', 'disable', NULL, 2),\r\n\t(7, 'empty', 'Fax', 'enable', NULL, 2),\r\n\t(8, 'equals', 'Region', 'clear', 'USA', 1),\r\n\t(9, 'equals', 'Region', 'focus', 'USA', 1),\r\n\t(10, 'equals', 'Region', 'require', 'USA', 1);\r\n\r\nCREATE TABLE IF NOT EXISTS `triggers` (\r\n  `id` int NOT NULL AUTO_INCREMENT,\r\n  `table` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,\r\n  `page` varchar(250) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,\r\n  `event` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,\r\n  `field` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL,\r\n  PRIMARY KEY (`id`)\r\n) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;\r\n\r\nINSERT INTO `triggers` (`id`, `table`, `page`, `event`, `field`) VALUES\r\n\t(1, 'customers', 'edit', 'change', 'Country'),\r\n\t(2, 'customers', 'edit', 'change', 'ContactName');<\/textarea><\/pre>\n<\/div>\n<h3>Server-side code<\/h3>\n<p>Server-side code goes to <strong>BeforeDisplay event<\/strong> of each page where this functionality needs to be implemented. In our situation this code goes to BeforeDisplay event of Customers table Edit page. The code itself is fairly straightforward. It just dumps all the data from actions and triggers tables and makes this data available in Javascript via proxy object. <\/p>\n<p>Note that for better code structure you need to create an external PHP or C# file, define a function there and place this code into that function. Then in all BeforeDisplay events <\/p>\n<p><strong>PHP code<\/strong><\/p>\n<div class=\"my-syntax-highlighter\">\n<pre><textarea id=\"mshighlighter\" class=\"mshighlighter\" language=\"php\" name=\"mshighlighter\" >\r\n$table = $pageObject->tName;\r\n$page = $pageObject->pageName;\r\n\r\n\/\/ get all the triggers for the current page and send it to Javascript\r\n$sql = DB::PrepareSQL(\"select * from triggers WHERE `table`=':1' and page=':2'\",\r\n    $table, $page);\r\n\r\n$triggers=array();\r\n\r\n$rs = DB::Query($sql);\r\nwhile( $data = $rs->fetchAssoc() )\r\n{\r\n    $triggers[] = $data;\r\n}\r\n\r\n\/\/ do the same for actions table\r\n\r\n$sql = DB::PrepareSQL(\"SELECT * FROM actions WHERE trigger_id IN (select id from triggers WHERE `table`=':1' and page=':2'\",\r\n    $table, $page);\r\n\r\n$actions=array();\r\n\r\n$rs = DB::Query($sql);\r\nwhile( $data = $rs->fetchAssoc() )\r\n{\r\n    $actions[] = $data;\r\n}\r\n\r\n$pageObject->setProxyValue(\"triggers\", $triggers);\r\n$pageObject->setProxyValue(\"actions\", $actions);<\/textarea><\/pre>\n<\/div>\n<p><strong>C# code<\/strong><\/p>\n<div class=\"my-syntax-highlighter\">\n<pre><textarea id=\"mshighlighter\" class=\"mshighlighter\" language=\"\" name=\"mshighlighter\" >\r\ndynamic actions = XVar.Array(), page = null, sql = null, triggers = XVar.Array();\r\ntable = XVar.Clone(pageObject.tName);\r\npage = XVar.Clone(pageObject.pageName);\r\nsql = XVar.Clone(DB.PrepareSQL(new XVar(\"select * from triggers WHERE `table`=':1' and page=':2'\"), (XVar)(table), (XVar)(page)));\r\ntriggers = XVar.Clone(XVar.Array());\r\nrs = XVar.Clone(DB.Query((XVar)(sql)));\r\nwhile(XVar.Pack(data = XVar.Clone(rs.fetchAssoc())))\r\n\t{\r\n\ttriggers.InitAndSetArrayItem(data, null);\r\n\t}\r\nsql = XVar.Clone(DB.PrepareSQL(new XVar(\"SELECT * FROM actions WHERE trigger_id IN (select id from triggers WHERE `table`=':1' and page=':2'\"), (XVar)(table), (XVar)(page)));\r\nactions = XVar.Clone(XVar.Array());\r\nrs = XVar.Clone(DB.Query((XVar)(sql)));\r\nwhile(XVar.Pack(data = XVar.Clone(rs.fetchAssoc())))\r\n\t{\r\n\tactions.InitAndSetArrayItem(data, null);\r\n\t}\r\npageObject.setProxyValue(new XVar(\"triggers\"), (XVar)(triggers));\r\npageObject.setProxyValue(new XVar(\"actions\"), (XVar)(actions));\r\nreturn null;<\/textarea><\/pre>\n<\/div>\n<h3>Javascript code<\/h3>\n<p>Javascript code goes to Javascript OnLoad event of the page where the action should happen, in our case this is Javascript OnLoad event of Customers table Edit page. The same idea with creating a Javascript function and calling from the external file is also valid here. <\/p>\n<p>You can extend this code by adding more conditions types and more actions. Check inline comments for more info. <\/p>\n<div class=\"my-syntax-highlighter\">\n<pre><textarea id=\"mshighlighter\" class=\"mshighlighter\" language=\"javascript\" name=\"mshighlighter\" >\r\n$('input, textarea, select, radio').on('change', function() {\r\n        \/\/ 'this' refers to the element that triggered the change event\r\n        const str = $(this).attr('id');\r\n        const match = str.match(\/^value_(.*?)_\/);\r\n        var name;\r\n        if (match) {\r\n            console.log('Value changed for:', match[1] , 'New value:', $(this).val());\r\n            name = match[1];\r\n            value = $(this).val();\r\n        }\r\n        \r\n        \/\/ lets see if we have a trigger associated with the current field\r\n        let triggers = proxy['triggers'];\r\n        let actions = proxy['actions'];\r\n        for (const trigger of triggers) {\r\n            if (trigger[\"field\"]==name ) {\r\n                \/\/ loop through actions array to see what kind of actions we need to perform\r\n                for (const action of actions) {\r\n                    if ( trigger[\"id\"] == action[\"trigger_id\"]) {\r\n                        \r\n                        var proceed = false;\r\n                        \r\n                        \/\/ check conditions\r\n                        \/\/ equals\r\n                        if (action[\"condition\"] == \"equals\") {\r\n                            if ( action[\"condition_value\"] == value ) {\r\n                                proceed = true;\r\n                            }\r\n                        }\r\n                        \/\/ not equals\r\n                        if (action[\"condition\"] == \"notequals\") {\r\n                            if ( action[\"condition_value\"] != value ) {\r\n                                proceed = true;\r\n                            }\r\n                        }\r\n                        \/\/ empty\r\n                        if (action[\"condition\"] == \"empty\") {\r\n                            if ( value.length==0 ) {\r\n                                proceed = true;\r\n                            }\r\n                        }\r\n                        \/\/ not empty\r\n                        if (action[\"condition\"] == \"notempty\") {\r\n                            if ( value.length!=0 ) {\r\n                                proceed = true;\r\n                            }\r\n                        }\r\n                        \r\n                        \/\/ do we have mathcing conditions \r\n                        \r\n                        if (proceed) {\r\n                            \/\/ show action\r\n                            if (action[\"action\"] == \"show\") {\r\n                                pageObj.showField(action[\"target\"]);\r\n                            }\r\n\r\n                            \/\/ hide action\r\n                            if (action[\"action\"] == \"hide\") {\r\n                                pageObj.hideField(action[\"target\"]);\r\n                            }\r\n                            \/\/ clear action\r\n                            if (action[\"action\"] == \"clear\") {\r\n                                Runner.getControl(pageid, action[\"target\"]).setValue();\r\n                            }\r\n                            \/\/ focus action\r\n                            if (action[\"action\"] == \"focus\") {\r\n                                Runner.getControl(pageid, action[\"target\"]).setFocus();\r\n                            }\r\n                            \/\/ require action\r\n                            if (action[\"action\"] == \"require\") {\r\n                                Runner.getControl(pageid, action[\"target\"]).addValidation(\"IsRequired\");\r\n                            }\r\n                            \r\n                        }\r\n\r\n                    }\r\n                }\r\n            }\r\n        }    \r\n    });<\/textarea><\/pre>\n<\/div>\n<p>Enjoy!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article we will discuss how to minimize the amount of code that handles Javascript on Add\/Edit pages. Making your code data-driven will help you easily manage forms with a huge numbers of fields. We will be taking care of functionality like showing\/hiding fields, making fields readonly, required, disabled etc. This approach will involve the following steps 1. Creating and populating database tables to store triggers ( when to apply the logic ) and actions ( what happens when trigger goes off ) 2&#8230;.<span class=\"clearfix clearfix-post\"><\/span><a href=\"https:\/\/xlinesoft.com\/blog\/2025\/09\/04\/moving-logic-from-javascript-to-the-database\/\" class=\"more-link\">Continue Reading <span class=\"screen-reader-text\">&#8220;Moving logic from Javascript to the database&#8221;<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,1,8],"tags":[],"class_list":["post-3222","post","type-post","status-publish","format-standard","hentry","category-asp-net","category-php-category","category-tutorials"],"_links":{"self":[{"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/posts\/3222","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/comments?post=3222"}],"version-history":[{"count":9,"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/posts\/3222\/revisions"}],"predecessor-version":[{"id":3234,"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/posts\/3222\/revisions\/3234"}],"wp:attachment":[{"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/media?parent=3222"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/categories?post=3222"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/xlinesoft.com\/blog\/wp-json\/wp\/v2\/tags?post=3222"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}