Transforming the Grid Picker

13567

Comments

  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    You know what could be cool? If you could somehow use a query picker to make sure, that the thing the user "searches" for does NOT exist already. Like a "this username is already taken"-kinda thing.

    A concrete example would be a request for the creation of shared mailboxes, where the requester should pick their own an email address and display name, but we need to make sure, that neither the username or display name already exists.

    Of course we can catch this in a runbook, but that's only after the request is created. So it would improve usability quite a bit, to be able to present the information for the user up-front.

    @Jeff_Lang
    That's good work, thanks a lot!
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    Is there a version of this that has been updated more recently than June 2nd, which someone could post?
  • Alex_MarshAlex_Marsh Premier Partner Advanced IT Monkey ✭✭✭
    You know what could be cool? If you could somehow use a query picker to make sure, that the thing the user "searches" for does NOT exist already. Like a "this username is already taken"-kinda thing.

    A concrete example would be a request for the creation of shared mailboxes, where the requester should pick their own an email address and display name, but we need to make sure, that neither the username or display name already exists.

    Of course we can catch this in a runbook, but that's only after the request is created. So it would improve usability quite a bit, to be able to present the information for the user up-front.

    @Jeff_Lang
    That's good work, thanks a lot!
    This would be amazing, would certainly save me a lot of effort for the mailbox runbooks we configure for customers. 
    +1 for the most recent version, would be very keen to get this in our dev environment to experiment with
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    I'll try to upload an update version one of the next days. Are you interested in having a version, which includes the @ShowHideOR-tag by Jeff Lang? The reason I'm asking is that I haven't tested that part at all, so I would be hesitant on just including and uploading it without testing it first, and testing it would take a bit longer time.
  • Adrian_MataiszAdrian_Mataisz Customer Advanced IT Monkey ✭✭✭
    @Konstantin_Slavin-Bo can you post the updated version?  You can include @ShowHideOr tag for now. Thank you!
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    Hi,

    Sorry for the long wait, I'm pretty swamped lately. Also, I've been working on trying to get this show/hide functionality to work, as even the simple one, where just the condition on the query prompt is taken into account, was causing trouble. Eventually, after a lot of fiddling, it dawned on me, that the whole approach (adding the ng-show attribute to the div) is completely wrong. This is because the angular only runs through the code once, at the compilation phase, and any other directive added to DOM after that isn't reachable. Angular attributes are meant to be added in directives and (normally) never injection into DOM. After this realization, I succeeded in adding a new compile step to the ROToolbox, which then forces the browser to rerun the angular compilation phase, such that the show/hide functionality is now fully operational, including the multi-conditions and @ShowHideOR made by @Jeff_Lang. This is not really a good solution / design, but it works (yaay!)

    TL;DR: It works now, the most-updated version of the toolbox is attached.

    New functionality / changes:
    • Changed the event listed for to sessionStorageReady, as consistently fires later than drawerCreated in my env. It seems to help some, but unfortunately it's not sufficient, so added a setTimeout() too with a 2 sec timeout (line 108, if you wanna play around with the timeout time) as a backup.
    • Both autocomplete pickers can now have up to three show/hide conditions, set on the tag, the text prompt and the query prompt. The three conditions are AND'ed by default.
    • @ShowHideOR: Takes the three conditions from above and OR's them instead of AND'ing, such that simply one of the conditions has to be true, before the autocomplete input is shown. Setting a condition on this tag does not do anything.
    • @ConfirmFields: Converts the next two text prompts to two "confirmation" inputs, where the text entered into them must be the same. Works by adding a dynamic regex-validation to the second text prompt, which is set to match the text in the first. Usage: Tag first, followed by two text prompts. On the second text prompt, add any .Net Regular Expression (e.g. .*) and a Custom ToolTip, which will be shown on mismatch.
    Hope this is useful to someone. Again, sorry for the long wait.
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    @Konstantin_Slavin-Bo

    Changed the event listed for to sessionStorageReady, as consistently fires later than drawerCreated in my env. It seems to help some, but unfortunately it's not sufficient, so added a setTimeout() too with a 2 sec timeout (line 108, if you wanna play around with the timeout time) as a backup.
    i found that the drawerCreated event was working correctly on chrome and Firefox, but had intermittent issues on windows 7 with IE, and didn't seem to run at all on Windows 10/IE. so i tried removing the () on the procedure name and found it worked in IE but no longer worked in Chrome/Firefox.

    It may not be the best way to do it, but i ended up adding 2 subscribes, and this seems to have solved our issues with it loading correctly. The start of the code shown below.

    app.events.subscribe('drawerCreated',transformRONonIE());
    app.events.subscribe('drawerCreated',transformROIE);

    function transformRONonIE() {
    transformRO();
    }
    function transformROIE() {
    transformRO();
    }

    function transformRO() {
    app.events.unsubscribe('drawerCreated',transformRONonIE);
    app.events.unsubscribe('drawerCreated',transformROIE);
    app.lib.mask.apply();

    we are not using a timeout at all, and since modifying it to the above, it has never failed to modify the page in all our testing on multiple PC's/Setups.




  • Adrian_MataiszAdrian_Mataisz Customer Advanced IT Monkey ✭✭✭
    edited September 2017
    Thank you @Jeff_Lang  and @Konstantin_Slavin-Bo . That's why is not working for me?  I have an intial question and had set the next 3 to show only when first is true, they all show including @Aucomplete tag and out the box query controller. I'm I doing something wrong?  Where do I add the code change you just posted?
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    the code above replaces what is just after the initial comment block, down to the line
    app.lib.mask.apply();
    I haven't tried @Konstantin_Slavin-Bo ; modification to use the sessionStorageReady instead of the drawerCreated yet though





  • Adrian_MataiszAdrian_Mataisz Customer Advanced IT Monkey ✭✭✭
    @Jeff_Lang I'll try your solution and remove line 108 timeout from the code povided by Konstantin. I'll let you know of the outcome. Thank you for your effort!
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    I finally got some time to merge the latest changes by @Konstantin_Slavin-Bo ; , and found that there were some issues if the recompile was run when there was no show/hide criteria, and also found that there were other instances where it was not being needed to be run at all.

    I've attached the latest copy of the one we are using, and will be putting into production shortly.

    the main changes from the one above are.
    1. running 2 app.events.subscribe, as it seemed to work correctly in some browsers without a () on the procedure to call and the rest of the browsers tested required the () on the end of the procedure name to call.
    2. added a new variable 'ngshowrecomp' to set if the recompile for the ngshow was required based on which of the subscribes mentioned in 1. were actually used by the browser.
    3. added a check using the 'ngshowrecomp' and if there were actually any show/hide criteria to decide if the recompile actually ran or not.

    after testing this appears to work correctly in all browsers tested here.

  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    @Jeff_Lang
    Oh, I completely missed those issues! Apparently IE doesn't support fetching the angular injector - good thinking on putting a var to check on in the non-IE transform, a beautifully simple low-tech approach! I'm trying out your two-function approach (with and without parentheses), and it seems to work (I'm still using the 'sessionStorageReady' event though, as it fires later than 'drawerCreated'). I'll try this on an internal RO we have, so the analysts can test it out. Thanks!
  • Peter_NordqvistPeter_Nordqvist Customer Adept IT Monkey ✭✭
    Nice work guys, but could you please provide some instructions, how to exactly use the functions, maybe some screenshots, i think it's a litte hard to understand how to use it.
    Thanks!
  • Adrian_MataiszAdrian_Mataisz Customer Advanced IT Monkey ✭✭✭
    I agree. I understand the @AutoComplete function/tag but not the others. SOme screenshots would be much appreciated. 
    Thank you guys!
  • Thomas_PeterThomas_Peter Customer IT Monkey ✭
    Hi Konstantin, your explanation is absolutely helpful - thanks very much !!


  • Peter_NordqvistPeter_Nordqvist Customer Adept IT Monkey ✭✭
  • Marek_LefekMarek_Lefek Customer Advanced IT Monkey ✭✭✭
    edited September 2017
    @Konstantin_Slavin-Bo Grate work! Thanks

  • Marek_LefekMarek_Lefek Customer Advanced IT Monkey ✭✭✭
    I have an issue with @AutoComplete and required field. I configure it as you wrote (and shown in pic below). 
    There is problem when user do not choose any option in the required field "Find a user" with @AutoComplete option. The popup with text ("This field is required") which field he has to check is not show. I change prompt "Start typing..." into required but it is the same situation. Do you have any idea how fix it. 



  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    @Marek_Lefek
    Oh, right. Somehow we all missed that part. As of now, there's no validation message on neither autocomplete fields (@AutoComplete and @MultiSelect). I've looked a bit on the code, and I'm not sure how we should add this.

    The _validationMessage span is added to DOM when a required field is not filled out, and I'm not sure where we can listen to any error events, to show our own error message. Maybe a mutation observer on when the span is added/removed, and then showing/removing our own error message? Does anyone have any suggestions or thoughts?
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    Okay, so far I've successfully detected when the original validation error message gets added, and used that event to add our custom error message. But, when the error is corrected, and the original message goes away, it does not get removed from DOM, but it gets hidden instead. And since the script already hides all the original elements, the state of the validation message does not change, so there's no way to detect that the error is now corrected, and the custom message should be hidden also.

    In other terms: We can successfully show an error, when a required field is not filled out, be we can't hide the message again, when the field then gets filled out. I don't know whether this functionality is something we want or would we then rather be without an error message at all? What do you guys think?
  • Marek_LefekMarek_Lefek Customer Advanced IT Monkey ✭✭✭
    Some our (especcialy new)  users have problems that can't find field which is required. They have missed it or have change the selected text in field. After this they are unable to register SR. 
    I think that is better to add custom error like "This field is required. Choose an option from list and save form" .

    Mayby it is possible to hide the message on page reload or focusin or focusout from field?
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    @Marek_Lefek
    Yeah, I agree that an error message is necessary. But I think this toolbox should strive to mimic the default behavior as much as possible. I would rather not have some functionality, than replicating it wrongly, as an inconsistent UX does more harm than good. In my own opinion anyways.

    That being said, I got it to work correctly! The error message is now displayed (and hidden) in the same manner as on other fields. I've attached an updated version.

    For the technically interested; I found an input element, which gets the attribute 'aria-invalid', so a mutation observer is listening for changes on that attribute, and displays / hides the validation message depending on that. Even though the optimal way would be to listen in on a validation property somewhere on one of the elements, I've been unable to find anything like that, so this seems like the next-best thing.

    This is the code added, which I've added right after where the HTML code is added to queryResult (line 356 and 549):

    AutoComplete:
    // Monitor input attribute to display custom error msg
    var obs = new MutationObserver (function(mutations) {     
      var invalidState = queryResults.find('div[data-control-type="checkboxGridByCriteriaOld"]').find('input#' + targetId).attr("aria-invalid");

      if(typeof invalidState != 'undefined' && $('span#ac' + targetId + '_errorMsg').length < 1) {
        $('input#ac' + targetId).parent().before('<span class="k-widget k-tooltip k-invalid-msg field-validation-error" id="ac' + targetId + '_errorMsg" role="alert"><span class="k-icon k-warning"></span> This is a required field.</span>');
      } else if(typeof invalidState == 'undefined' && $('span#ac' + targetId + '_errorMsg').length > 0) {
        $('span#ac' + targetId + '_errorMsg').remove();
      }
    });

    obs.observe(document.querySelectorAll('div[data-control-type="checkboxGridByCriteriaOld"] input[id="' + targetId + '"]')[0], {attributes: true, attributeFilter: ['aria-invalid'], childList: false, characterData: false, subtree:false});

    MultiSelect:
    // Monitor input attribute to display custom error msg
    var obs = new MutationObserver (function(mutations) {     
      var invalidState = queryResults.find('div[data-control-type="checkboxGridByCriteriaOld"]').find('input#' + targetId).attr("aria-invalid");

      if(typeof invalidState != 'undefined' && $('span#ms' + targetId + '_errorMsg').length < 1) {
        $('ul#ms' + targetId + '_taglist').parent().parent().before('<span class="k-widget k-tooltip k-invalid-msg field-validation-error" id="ms' + targetId + '_errorMsg" role="alert"><span class="k-icon k-warning"></span> This is a required field.</span>');
      } else if(typeof invalidState == 'undefined' && $('span#ms' + targetId + '_errorMsg').length > 0) {
        $('span#ms' + targetId + '_errorMsg').remove();
      }
    });

    obs.observe(document.querySelectorAll('div[data-control-type="checkboxGridByCriteriaOld"] input[id="' + targetId + '"]')[0], {attributes: true, attributeFilter: ['aria-invalid'], childList: false, characterData: false, subtree:false});
  • Marek_LefekMarek_Lefek Customer Advanced IT Monkey ✭✭✭
    Do I have something more than replace the ROT file? I replace the ROT file, but the mesage is not showing (test on IE11, Chrome)
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    @Marek_Lefek
    No, replacing custom_ROToolbox.js is all it takes. Try resetting your browsers cache (CTRL + F5 while on the page); the old file is probably cached in local storage.

  • Adrian_MataiszAdrian_Mataisz Customer Advanced IT Monkey ✭✭✭
    It works for me with @AutoComplete , thank you sir!
  • Marek_LefekMarek_Lefek Customer Advanced IT Monkey ✭✭✭
    @Konstantin_Slavin-B it looks, that it don't work with "Next page" button. On the "Save" button it works fine.
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    I've been playing with this a bit more, and done the following changes to the attached version.

    1. Moved the Recompile for Angular Elements to a separate procedure, which can be called from anywhere.
    2. removed the browser check for the above to perform or not perform the recompile, and added a browser independent check.
    3. as the browser is no longer needed to be known for the above, removed the specific calls  and variables for checking if the browser was IE or Not.
    4 merged in the modifications for the Required fields above by  @Konstantin_Slavin-Bo into the version i have been working on.
    5. added 2 New @ options
    5.A. @ShowHideCriteria placed before any item (Except for a Query) will allow the criteria put on this entry to be added to the following Item using AND ('&&')
    5.B. @ShowHideORCriteria placed before any item (Except for a Query) will allow the criteria put on this entry to be added to the following Item using OR ('||')

    NOTE: If using the options described in 5.A. and 5.B. and you are using a Boolean checkbox as the criteria, the criteria will be transformed so that it should work correctly always without having to check and uncheck boxes to set initial values The changes to the criteria treat a Boolean that has not yet been set at all as a false instead of treating it as a separate null value.

    I have tested these new criteria options referring to Boolean's and Drop down lists, although as always, make sure you test yourselves before using in production :)

    also modified to use the sessionStorageReady subscribe.



  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    just a small update, but might be worth while for some

    added a sort to the @AutoComplete and @MultiSelect, so they show all items on the drop down list in ascending Order, making it easier to find items without typing extra
Sign In or Register to comment.