async await in setValidator function

251 views
Skip to first unread message

Arbaz Sheikh

unread,
Feb 2, 2021, 1:49:20 AM2/2/21
to Blockly
Hello,

I created a custom Typeahead field in blockly which shows suggestion(dropdown) as you type in the field.
I use an API call to backend to get the results and update the dropdown whenever user type something in the field.
Now i want to set Validator on the field to check if the entered value matches the option in the dropdown and show error if it doesnt and set to empty.
I made the API call inside setValidator and then check if entered value matches, the code for which is below:-

    Blockly.Extensions.register('dynamic_UCUM', function (block) {
      var ucum_field = this.getField('UCUM_suggestions');
      // Empty text field should not display any suggestion
      var ucum_validator = (newValue) => {
        if (!newValue) {
          current.updateMenuGenerator(ucum_field, []);
        }
        else {
          current.restService.getUCUM(newValue).subscribe(result => {
            var names = new Array();
            var ucum_suggestions: any[] = result[3];
            ucum_suggestions.forEach(element => {
              names.push(element[0] + " " + element[1])
            });
            current.updateMenuGenerator(ucum_field, names);
          });
        }
        if (!(ucum_field as any).menuGenerator.includes(newValue)) {
          return null;
        }
        return newValue;
      }
      ucum_field.setValidator(ucum_validator);
    });

The problem here is that the if block check of includes gets executed before API response and hence the validation is not proper.
I also used async await but it is not working.
Can anyone suggest me how to tackle this problem so that the if check gets executed after the API response in setValidator Or alternate way to do this

Beka Westberg

unread,
Feb 2, 2021, 6:51:22 PM2/2/21
to blo...@googlegroups.com
Hello,

> I created a custom Typeahead field in blockly which shows suggestion(dropdown) as you type in the field.
That sounds like a really cool field :D I hope someone here can help you get it working!

I'm not very familiar with doing API calls like this :/ but it might help if you provide a few more details about your problem. For example, you say "hence the validation is not proper", does this mean that it's getting validated against the /previous/ API response? or does it mean something else? It might also be helpful to provide the async/await code that you tried, and a gif/video of what you're seeing.

Sorry I can't be more helpful :/ Hopefully someone else will have more insights for you!
--Beka

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/899814fc-5eb3-499d-8c32-7e1d8d57d8e5n%40googlegroups.com.

Arbaz Sheikh

unread,
Feb 3, 2021, 1:29:32 AM2/3/21
to Blockly
Yes, it's getting validated against the /previous/ API response with the above code.

The async await code :-

Blockly.Extensions.register('dynamic_entity', function (block) {
      var entity_field = this.getField("entity_suggestions");
      var entity_validator = async (newValue) => {
        // Empty text field should not display any suggestion
        if (!newValue) {
          await current.updateMenuGenerator(entity_field, []);
          return null;
        }
        else {
          await current.restService.getEntities(newValue)
            .subscribe(result => {
              var names = new Array();
              var data: any[] = result["data"];
              names = data[1];
              current.updateMenuGenerator(entity_field, names);
              // return result;
            });
          if (!(entity_field as any).menuGenerator.includes(newValue)) {
            return null;
          }
          return newValue;
        }
      };
      entity_field.setValidator((async () => {
        return(await entity_validator)
      })())
    });

is giving error
core.js:6241 ERROR TypeError: b.call is not a function
    at CustomFields.Typeahead.Blockly.Field.setValue (vendor.js:140686)
    at CustomFields.Typeahead.Blockly.Field.fromXml (vendor.js:140671)
    at Object.Blockly.Xml.domToField_ (vendor.js:140389)
    at Object.Blockly.Xml.domToBlockHeadless_ (vendor.js:140386)
    at Object.Blockly.Xml.domToBlock (vendor.js:140381)
    at Blockly.VerticalFlyout.Blockly.Flyout.placeNewBlock_ (vendor.js:141053)
    at Blockly.VerticalFlyout.Blockly.Flyout.createBlock (vendor.js:141047)
    at Blockly.TouchGesture.Blockly.Gesture.updateIsDraggingFromFlyout_ (vendor.js:140643)
    at Blockly.TouchGesture.Blockly.Gesture.updateIsDraggingBlock_ (vendor.js:140644)
    at Blockly.TouchGesture.Blockly.Gesture.updateIsDragging_ (vendor.js:140646)


If this is not the proper way, can you suggest me the correct way to do this



Mark Friedman

unread,
Feb 3, 2021, 2:03:49 PM2/3/21
to blo...@googlegroups.com
I don't know the details of the API that you're using, but it looks like the call to current.restService.getUCUM(newValue).subscribe takes a callback function (i.e "result => { ... }") as an argument and that callback is called when the API returns.  Consequently, I would try placing the validation code inside that callback function.

Hope that helps.

-Mark


Arbaz Sheikh

unread,
Feb 3, 2021, 2:10:16 PM2/3/21
to blo...@googlegroups.com
Ok I'll try this but how should i handle the response (promise) from async function entity_validator

You received this message because you are subscribed to a topic in the Google Groups "Blockly" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/blockly/_3C3y0N0tvE/unsubscribe.
To unsubscribe from this group and all its topics, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/CAOk7GcT0Mf552pet4k8WnuzihjwCaE4Jvt_h2jR-%3D7gDAN8nKw%40mail.gmail.com.

Mark Friedman

unread,
Feb 3, 2021, 6:30:29 PM2/3/21
to blo...@googlegroups.com
Sorry if I was unclear.  I was referring to the original code that you gave.  It wasn't clear to me whether you really needed the async/await version or whether that was just something you tried out in the hopes that it would fix your problem.  If you really need the async/await version then I would suggest first seeing if there is a version of your getUCUM API that returns a promise and then await that rather than using the version that requires a callback.  If such a version of the getUCUM API doesn't exist, then I would suggest "promisifying" the getUCUM.subscribe function.  There are any number of implementations of promisify out there - a simple Google search should find you one.

-Mark


Arbaz Sheikh

unread,
Feb 3, 2021, 8:19:58 PM2/3/21
to blo...@googlegroups.com
It's still not helping by adding your suggested changes in the original code as the entity_validator function flow is not waiting for the subscribe callback response and getting executed anyways.

Eric Edem

unread,
Feb 3, 2021, 10:24:01 PM2/3/21
to Blockly
I think some of the confusion here might be coming from people's lack of understanding of the domain-specific API that you are calling.

I'd recommend trying to make a code sandbox that decouples that network call from your use case. You can create an async function to mimic a network call by returning a promise and resolving with a setTimeout().

Best,
Eric

Arbaz Sheikh

unread,
Feb 4, 2021, 2:34:25 AM2/4/21
to Blockly
As far as i know  we cannot get synchronous result out of an asynchronous operation in Javascript. We just cannot do it. If any part of your operation is async, the entire result must be async and you must either use a callback, a promise or some other such mechanism to communicate when the operation is done and the result is ready.
Here the setValidator function excepts a string or null value and does not accept an async response. I am still not sure how will i achieve this functionality

Michael Noel

unread,
Apr 8, 2021, 9:39:17 PM4/8/21
to Blockly
I don't know if you're still working on this but I was successful when using something like this:

(async (block) => {
      console.log(block.type);
      await apiCall();
})(this);
Reply all
Reply to author
Forward
0 new messages