Not In Array- is now possible

I’m trying to set up a multi select using Wappler’s select and a couple of arrays. It’s working really well for a Create form, but for Updating I want to restrict the list of choices to exclude those already selected.

Say I have a list of options 1,2,3 coming from server connect “getPermissions.data.getPermissions”.

Of the options (1,2,3) number 1 is already allocated and listed in “arrPermissionsSelected.items” so I want to show 2 and 3 in the select which references “arrPermissionsSelection” as it’s source.

<dmx-array id="arrPermissionsSelection" dmx-bind:items="getPermissions.data.getPermissions.where(permission_id, arrPermissionsSelected.items, &quot;inArray&quot;).values('permission_id')"></dmx-array>

The code above gets me 1 as it uses inarray. If there was the option of NOT inarray it would give me what I need, 2 and 3…but that’s not an option I can see? Is there any way of achieving this?

So this is the full code for the select:

<div class="col-12 mt-2" dmx-hide="(varProgSelectVisible.value != 1)" dmx-animate-enter.duration:1500.delay:200="fadeIn" dmx-animate-leave.duration:1500.delay:200="fadeOut"

                                            dmx-show="(varProgSelectVisible.value == 1)">

                                            <dmx-array id="arrProgrammesSelected" dmx-bind:items="editStaffView.data.queryProgrammes.values(`programme_id`)"></dmx-array>

                                            <dmx-array id="arrProgrammesSelection" dmx-bind:items="getProgList.data.getProgs.values(`programme_id`)"></dmx-array>

                                            <select id="select1" class="custom-select" dmx-bind:options="getProgList.data.getProgs.where(`programme_id`, arrProgrammesSelection.items, &quot;inArray&quot;)" optiontext="programme_name"

                                                optionvalue="programme_id" name="updateStaffProgrammes"

                                                dmx-on:changed.debounce:200="editStaffView.formUpdateStaff.arrProgrammesSelected.addUniq(value);;editStaffView.formUpdateStaff.arrProgrammesSelection.remove(value)">

                                                <option selected="" value="" disabled>Select Programmes</option>

                                            </select>

                                            <div id="repeatProgSelect" is="dmx-repeat" dmx-bind:repeat="arrProgrammesSelected.items">

                                                <div class="badge badge-pill" dmx-on:click="editStaffView.formUpdateStaff.arrProgrammesSelected.removeAt($index);editStaffView.formUpdateStaff.arrProgrammesSelection.addUniq($value)"

                                                    dmx-style:background-color="getProgList.data.getProgs.where(`programme_id`, $value, &quot;==&quot;).values('programme_colour')">

                                                    {{getProgList.data.getProgs.where(`programme_id`, $value, "==").values('programme_shortcode')}} <i class="fas fa-times"></i> </div>

                                            </div>

                                        </div>

The array arrProgrammesSelection currently returns ALL programmes, I would like for it to exclude the programmes listed in arrProgrammesSelected. The on:change event in the select and on:click event in the badges manages the arrays on user interaction, it’s just looking for a way to populate the initial lists.
This is the kind of thing I think the array binding should look like, if I could just change the inArray to NOTinArray!

<dmx-array id="arrProgrammesSelection" dmx-bind:items="getProgList.data.getProgs.where(programme_id, arrProgrammesSelected.items, &quot;inArray==0&quot;).values(&quot;programme_id&quot;)"></dmx-array>

If anyone has any suggestions I’d be really grateful! I’ve tried not equal, it show the list perfectly to start but once a selection is made it only updates to the current selection. I think it would be achievable through flows but seems like a sledgehammer to crack a nut!

Using a custom DMX Formatter would be the best solution right now. Although this would make for a good addition I suppose.

You will have to create a formatter, say whereNotInArray, and use JS to filter and return the list.

dmx.Formatter('array', 'whereNotInArray', function (val, propertyName, arrayValues) {

    if (arrayValues == null || arrayValues.length == 0)
        return null;

    if (propertyName == null)
        throw Error("Incorrect parameters.");

    var returnVal = [];
    
    for (var i = 0; i < val.length; i += 1) {
        var isInArray = false;

        for (var j = 0; j < arrayValues.length; j += 1) {
            if (val[i][propertyName] == arrayValues[j]) {
                isInArray = true;
                break;
            }
        }

        if (!isInArray)
            returnVal.push(val[i]);
    }

    return returnVal;
});

Call it like so:

getProgList.data.getProgs.whereNotInArray('programme_id', arrProgrammesSelected.items)

Haven’t tested the JS. So please debug if any issues. Run this script after page load has completed.

More on client-side & server-side custom formatters/modules:

I think there is a better way to compare between two array for a NOT IN ARRAY comparison rather than using nested loops.
See if you can find anything on Google. This is just a rough code I have written.

Short version:

dmx.Formatter('array', 'whereNotInArray', function(val, prop, arr) {
  if (!Array.isArray(arr) || !arr.length) return val;

  return val.filter(function(item) {
    return arr.indexOf(item[prop]) == -1;
  });
});
4 Likes

dmxFormatter.zip (7.8 KB)

I added notContains and notInArray to the where formatter.

usage:

getProgList.data.getProgs.where('programme_id', arrProgrammesSelected.items, 'notInArray').values('programme_id')
9 Likes

This works perfectly thanks so much!!

I can see quite a number of use cases so, hopefully, it will be a really useful addition.

Patrick, for Testing Is your “dmxFormatter.js” script in the .zip file then to overwrite the existing file loaded in a typical Wappler application?

I’m working in German websites where exactly this sort of language support for umlaut characters is necessary.

I’m using Wappler Beta 5.

Thank you!

You need to replace the local version of the dmxFormatter.js in your project and upload it to your server.

Not sure what has this to do with the additions added by Patrick in the zip? It’s adding a Not In Array option which has nothing to do with any German characters.

I was referring to this reference in this thread – Custom Formatter
“More on client-side & server-side custom formatters/modules:”

& https://community.wappler.io/t/please-add-specific-language-support-for-slugify-formatter/15425

Ok, but that’s a separate topic not related to what’s being discussed here.

1 Like