A JavaScript library allows showing/hiding "dependent" field(s) if the value of the “dependee” field matches the right condition.

Overview

MF Conditional Fields

A JavaScript library that show/hide form elements based on the value of one field or many.

MF Conditional Fields

Advantages

  • Lightweight & fast.
  • Comes with a number of different operators.
  • Supports complex conditional rules ( simple as well as grouped rules).
  • Supports dynamic forms ( forms that are updated with new elements after the DOM is loaded ).
  • Supports all form elements regardless of their type ( input, select..etc ).

Disadvantages

  • JSON based and large conditions, which makes writing rules a bit frustrating. However, you can always write you own helpers to create rules faster ( See jQuery and PHP usage for examples )

When To Use

This library is best suited for complex conditions and dynamically generated fields. Field conditions are written in JSON format and it can be hard to generate these manually.

If you plan on using this for your PHP project, make sure to check out the PHP Usage section below.

If you want to use jQuery, you'll need to write your own function or plugin to supply your rules as array of object to mfConditionalFields( '.formSelecotr', {rules: rulesArray} ). ( see Block based rules section for the correct format )

How To Use

  1. Load dist/mf-conditional-fields.min.js.

  2. Add your JSON formatted conditions inside a JS element or to the field you want to show/hide inside a data-conditional-rules attribute.

  3. Call mfConditionalFields('form') (replace form with your form selector)

  4. Let the magic happen

Available Options

To give you more control over the conditional elements, mfConditionalFields offers a set of options that you can specify to change how the library interacts with conditional elements. The options can used like this:

mfConditionalFields('form', {
  rules: 'inline', // accepts `inline`, `block` and array of objects ( see below for examples ).
  dynamic: false, // If set to `true` the library will handle elements added after the DOM is loaded ( see below for examples ).
  unsetHidden: false, // If set to `true` the library will unset the value of any hidden fields.
  disableHidden: false, // If set to `true`, any hidden fields will be set to `disabled`.
  debug: false, // If set to `true` the library will show hints in the console when things aren't working as expected.
  depth: 3 // This allows you to set how deep should the library go in showing/hiding dependent fields.
});

Inline Based Rules

{
   "container":".element-to-show-hide",
   "action":"show",
   "logic":"or",
   "rules":[
      {
         "name":"parent_field_name",
         "operator":"is",
         "value":"parent_field_targeted_value"
      }
   ]
}

Block Based Rules

[
    {
       "field":"field1_name",
       "container":".element-to-show",
       "action":"show",
       "logic":"or",
       "rules":[
          {
             "name":"parent_field_name",
             "operator":"is",
             "value":"parent_field_targeted_value"
          }
       ]
    },
    {
        "field":"field1_name",
        "container":".element-to-hide",
        "action":"hide",
        "logic":"or",
        "rules":[
          {
             "name":"parent_field_name",
             "operator":"isnot",
             "value":"parent_field_targeted_value"
          }
       ]
    },
]

Field

The name attribute of the field you want to show/hide/enable/disable based on the provided rules. Note that this can only be used in the block based rules, inline based rules don't require this. ( if the bold terms don't make sense yet, please keep reading )

Container

The conditional field parent element where you want to perform the hiding/showing action, leave empty to show/hide the field itself.

Action

  • show
  • hide
  • enable
  • disable

Logic

  • or ( meeting one of the rules is enough to perform the action )
  • and ( all the rules must be met to perform the action )

Rules

This should contain the rules you want to meet before showing/hiding the field. The rules can accept one rule in simple format {"name": "a", "operator": "is", "value": "yes"} or multiple rules [{"name": "a", "operator": "is", "value": "yes"}, {"name": "b", "operator": "is", "value": "no"}]

Note: grouped rules are also supported, if you need to create complex conditions, just store them as set of groups in the dependant field rules. Here is a sample of groups:

[
    {
        "field":"dependant_field",
        "container":".field_container",
        "action":"show",
        "logic":"or",
        "rules":[
            {
                "relation":"and",
                "group":[
                    {
                        "name":"ruling_field1",
                        "operator":"is",
                        "value":"One"
                    },
                    {
                        "name":"ruling_field2",
                        "operator":"is",
                        "value":"Two"
                    }
                ]
            },
            {
                "relation":"and",
                "group":[
                    {
                        "name":"ruling_field3",
                        "operator":"b",
                        "value":"One"
                    },
                    {
                        "name":"ruling_field4",
                        "operator":"is",
                        "value":"Two"
                    }
                ]
            },
            {
                "relation":"and",
                "group":[
                    {
                        "name":"ruling_field5",
                        "operator":"is",
                        "value":"None of the above"
                    }
                ]
            }
        ]
    }
]

Name

The name attribute of the parent field where the script should be listening for changes

Operator

Comparision operators to compare between the parent field value and the rule value

  • is
  • isnot
  • greaterthan
  • lessthan
  • contains
  • doesnotcontain
  • beginswith
  • doesnotbeginwith
  • endswith
  • doesnotendwith
  • isempty
  • isnotempty

Value

The parent field value we should be watching for to perform the action, this can accept one value, if you want to use more values, you'll need to create more rules.


Usage

PHP Usage ( Inline Based Rules )

  • Create a helper function

    function get_mf_conditional_rules( $action, $rules, $logic = 'or', $container = '.default-field-container' ) {
    
      return json_encode( array(
              'container' => $container,
              'action' => $action,
              'logic' => $logic,
              'rules' => $rules,
            ));
    }
    
  • Create your form and give it an id or class to use for initialization

      ?>
          <form id="example_form">
          </form>
      <?php
    
  • Create parent field (trigger)

      ?>
          <div class="form-group">
              <label for="field1">Parent Field</label>   
              <input type="checkbox" name="parent_field" id="field1" value="yes"/>
          <div>
      <?php
    
  • Create you conditional rules and field like this (dependant field)

      $condition1 = get_mf_conditional_rules( 'show', array(
        'name' => 'parent_field',
        'operator' => 'is',
        'value' => 'yes'
      ) );
      ?>
          <div class="form-group">
            <label for="field2">Dependant Field</label><br>
            <input type="text" name="dependant_field" id="field2" data-conditional-rules="<?php echo htmlspecialchars($condition1); ?>" />
          </div>
      <?php
    
  • Load the library and Initialize conditional fields

      ?>
        <script src="../dist/mf-conditional-fields.min.js"></script>
        <script>
          mfConditionalFields('#example_form');
        </script>
      <?php
    

Plain HTML Usage ( Block Based Rules )

  • Create your form and give it an id or class to use for initilizations

      <form id="example_form">
      </form>
    
  • Create parent field (trigger)

      <div class="form-group">
          <label for="field1">Parent Field</label>   
          <input type="checkbox" name="parent_field" id="field1" value="yes"/>
      <div>
    
  • Create your conditional field (dependant field)

      <div class="form-group">
        <label for="field2">Dependant Field</label><br>
        <input type="text" name="dependant_field" id="field2" />
      </div>
    
  • Create a script element and give it the id attribute rules-mf-conditional-fields

      <script type="text/x-rules" id="rules-mf-conditional-fields">
          // Rules here
      </script>
    
  • Create your conditions based on the block based rules format and put them inside the script element you created

      [
         {
            "field":"dependant_field",
            "container":".form-group",
            "action":"show",
            "logic":"or",
            "rules":{
               "name":"parent_field",
               "operator":"is",
               "value":"yes"
            }
         }
      ]
    
  • Load the library and Initialize conditional fields ( make sure to pass an object with rules property set to block as a second arguement when calling mfConditionalFields )

    <script src="../dist/mf-conditional-fields.min.js"></script>
    <script>
      mfConditionalFields('#example_form', {rules: 'block'});
    </script>
    

Usage With Dynamic Forms

To use dynamic forms functionality, you must use inline based rules and initiaize the form like this

mfConditionalFields('#example_form', {
  rules: 'inline', 
  dynamic: true
  });

Then, you must trigger the event mfConditionalFormUpdated each time you add or remove fields. After you do that, the script will implement conditional logic to any new conditional fields in form. ( change the value add to remove if a field is remove )

let mfEvent = new CustomEvent("mfConditionalFormUpdated", { "detail": { "action": "add" } });
document.getElementById('example_form').dispatchEvent(mfEvent);

Making changes ( development )

Want to make changes to the source code? Simply install dependencies using npm install and watch for changes using the command npm run watch.

Once the command npm run watch is executed, you can start making changes to /src/mf-conditional-fields.js and the file will be automatically minified and exported to /dist/mf-conditional-fields.min.js.

Once done and you want to generat a clean minified version ( without source mapping ), run npm run build.


Have an issue or suggestion?

Feel free to share any issues or feature requests by creating an issue

Want to contribute?

Fork, change, send pull request!

Comments
  • Uncaught RangeError: Maximum call stack size exceeded

    Uncaught RangeError: Maximum call stack size exceeded

    The field cannot work with a dependable field that depends on another fields. Here is the used [{ "field": "display", "container": ".hsel_display", "action": "show", "rules": [{ "name": "choice", "operator": "is", "value": "lca_debug" }, { "name": "choice", "operator": "is", "value": "lca_awm_debug" }], "logic": "or" }, { "field": "script", "container": ".hsel_script", "action": "hide", "rules": [{ "name": "logpath", "operator": "isnotempty", "value": "" }, { "name": "display", "operator": "is", "value": "0" }, { "name": "log", "operator": "is", "value": "0" }], "logic": "or" }]

    For quicker test Here's the HTML

    bug 
    opened by icaxis 4
  • Bump grunt from 1.5.2 to 1.5.3

    Bump grunt from 1.5.2 to 1.5.3

    Bumps grunt from 1.5.2 to 1.5.3.

    Release notes

    Sourced from grunt's releases.

    v1.5.3

    • Merge pull request #1745 from gruntjs/fix-copy-op 572d79b
    • Patch up race condition in symlink copying. 58016ff
    • Merge pull request #1746 from JamieSlome/patch-1 0749e1d
    • Create SECURITY.md 69b7c50

    https://github.com/gruntjs/grunt/compare/v1.5.2...v1.5.3

    Changelog

    Sourced from grunt's changelog.

    v1.5.3 date: 2022-04-23 changes: - Patch up race condition in symlink copying.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Form Object RadioNodeList element fix

    Form Object RadioNodeList element fix

    HTMLFormElement.elements returns an HTMLFormControlsCollection, storing either RadioNodeLists or Elements. This PR proposes a fix for the RadioNodeList case - it currently fails on theField.setAttribute (in updateForm).

    To test, simply adds multiple inputs with the field name array syntax:

    <label>Last name</label>
    <input name="last_name[]">
    
    <label>Last name</label>
    <input name="last_name[]">
    

    Thanks for this great library!

    opened by laemtl 1
  • [Improvements] Add disable action

    [Improvements] Add disable action

    At the moment the only action supported are hide and show. A nice addition would be a disable action.

    This can be useful to disable certain field until a correct value is entered. And also the most used use case is to disable the button, for example if the privacy policy is not accepted.

    I have digged a bit trough the code, but seems not a simple implementations at the moment. It would require some code refactoring.

    opened by Tropicalista 1
  • Improvements

    Improvements

    1. This project is in desperate need of a Linter like ESLint. I tried reading the source code on GitHub I couldn't follow it. Spacing inconsistencies is making it hard to follow
    2. I would prefer using the hidden boolean attribute instead of accessing the element style and setting it none.
    3. Controlling the element visibility isn't enough, you have to disable the element using the disabled boolean attribute to avoid submitting its value. You can use that either on the form input or the fieldset.
    4. Your library shouldn't be logging anything to the console. You can use that in debugging if you want but you should either remove it manually or by a script when you ship it. If you want to show an error or a warning using console.warn or throw an error.
    5. Using IDs should be prohibited because if the user wants to use your library on more than one instance on the same page, he will have to create elements with the same ID. It's invalid.
    6. It's advised to check for the global window object before adding stuff to it. In the case of SSR, the window object isn't available and it would break the build. Finally, try to publish it on NPM, it will be a great experience.
    enhancement 
    opened by bomsn 0
Owner
Ali Khallad
Ali Khallad
Weather Condition App is a mobile application that has a category of countries in the home age and the users can access to weather of each country.

World Weather This is a SPA react-app project that is built using two APIs. And users can select and choose countries and states and get their updated

Ahmad Zamir Yousufi 2 Oct 10, 2022
This web application is a type of a scoreboard showing the names and current scores of the leading competitors in any field which is using API's to get and set data

Leaderboard-project This web application is a type of a scoreboard showing the names and current scores of the leading competitors in any field which

Ravi Teja 5 Feb 11, 2022
Email Genie Allows autocomplete on email field by providing a list of domain suggestions (gmail.com, outlook.com, etc.).

Allows users to easily and quickly complete an email field by providing a list of domain suggestions (gmail.com, outlook.com, etc.). This package stands out for its flexibility, its compatibility with libraries / frameworks, but especially its use of basic HTML and Javascript functionalities that maximize the native behavior of desktop AND mobile browsers.

Simon Arnold 3 Oct 4, 2022
A Jquery plugin that allows user to enter multiple emails using one input field

multi-emails A Jquery plugin that allows user to enter multiple emails using one input field Usage $("...").multiEmails() Options color textColor font

null 1 Aug 26, 2022
Library for showing Gravatars or generating user avatars.

Avatar Avatar is a JavaScript library for showing Gravatars or generating user avatars. Examples There are several examples on the website. import Ava

Matthew Callis 198 Dec 22, 2022
Kyrillos Hany 14 Aug 10, 2022
A free JavaScript plugin to create custom right click context menus.

CtxMenu (Javascript) A modern, light weight, object oriented solution for adding right click context menus for your website. demo Installation Downloa

Nils Söderman 18 Oct 13, 2022
Small example showing how you can make game sprite animations using CSS with Javascript movement.

Hi there, I'm Björn Hjorth ?? I like combining the web and game development, if you like what you see please do not be a stranger and say "Hi" on Twit

Björn Hjorth 29 Nov 9, 2022
Tiny JavaScript library (1kB) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.

Zero dependency tiny JavaScript library (1kB bytes) by CurrencyRate.today, providing simple way and advanced number, money and currency formatting and removes all formatting/cruft and returns the raw float value.

Yurii De 11 Nov 8, 2022
A VS Code extension to practice and improve your typing speed right inside your code editor. Practice with simple words or code snippets.

Warm Up ?? ??‍?? A VS Code extension to practice and improve your typing speed right inside your code editor. Practice with simple words or code snipp

Arhun Saday 34 Dec 12, 2022
If you want to know more about your favorite TV show then you've come to the right place!

Ultimate Show Guide We want to introduce you this web page that will help you to manage all your favourite TV series from place. ??️ Desktop version H

William Morales 6 Jun 23, 2022
Demonstration of how you build full-stack, typed, NPM packages, the right way

NPM Packages - The Right way This repository aims to demonstrate how to build NPM packages the right way. my-package should import the shared code, bu

VulcanJS 61 Nov 27, 2022
Move all the disks from the left hand post to the right hand post, only moving the disks one at a time and a bigger disk can never be placed on a smaller disk.

Hanoi Tower Description The Tower of Hanoi was a famous problem posed by a mathematician in 1883, The "puzzle" is to move all the disks from the left

Dustin J Sellers 1 Feb 5, 2022
📸 A command-line tool to generate code images of your local code right away from the terminal

?? rayli ?? A command-line tool to generate code images of your local code right away from the terminal Usage Commands Usage $ npm install -g rayli $

buidler's hub 45 Nov 4, 2022
My terrible attempt at a promposal. Update: She said yes LMFAO Update Update: I got friendzoned right after 😭

TypeScript Next.js example This is a really simple project that shows the usage of Next.js with TypeScript. Deploy your own Deploy the example using V

John Li (Tet) 7 Oct 27, 2022
Sample apps showing how to build music and video apps for Xbox using a WebView.

description languages name page_type products urlFragment Sample showing how to build music and video apps using primarily web technologies for Xbox.

Microsoft 11 Dec 14, 2022
Simple components showing differences in each major frontend web framework.

Web Frameworks A collection of simple components in each of the leading frontend web frameworks. So far, covering React, Vue, Angular, Svelte and Soli

Daniel Still 21 Nov 27, 2022
Example application showing how to use single-table design with GraphQL and DynamoDB

GraphQL + DynamoDB -- Single-table example This repository includes an example of building a GraphQL API with DynamoDB using a single DynamoDB table.

Alex DeBrie 19 Dec 13, 2022