Home Analyst Portal

Useful events to attach custom code to?

Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
Rather than trying to be clever and take a significant amount of time to figure this out with trial and error, perhaps the most direct solution is to ask:

What are the (best) events that are already firing on the forms for us to bind custom functions to?

In particular, I am interested in the save event, and also the toast notifications that began appearing with v8.0.  However, a more comprehensive list could help us all!

I am using a mutation observer to determine when form validation errors occur.  Would it not be better to create an event handler that fires the original event handler plus my code?  Also, the new toast notifications interfere with other customizations.  If I could allow them to continue but capture the event and handle it in a more compatible manner, that would be even better.

Perhaps there are more / better examples than what I have stated here, as well!

Best Answers

Answers

  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    +1
    A nice event to subscribe to for when a page is fully loaded would be great! Having to rely on document(ready) and having to resort to using timers is not optimal. If Cireson wants this portal to be truly customizable, we need more events on various points, so we can trigger our customizations at the right moment.
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    While I was looking for a big list of them (which assumes that one exists, in the first place! :)), I think you are starting to help us build one, @Konstantin_Slavin-Bo.  Thank you!

    These are good examples of exactly what I was talking about.  @john_doyle 's post was what prompted me to ask this question, not coincidentally.

    Let's keep them coming!  Does anyone else know of any good events to key off of?  Sadly, my own experience is currently limited to the user-prompted events in some of the Kendo controls.
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    Yeah, well Cireson wasn't answering, so I figured we can start compiling our own list. A useful tip to see which (Cireson-created) events fires at different points, is to add a console.log(event) to the publish function in \Scripts\app\app.lib.js

    It will then print the events, which are published to the message bus in the devtools console.

    Of course this only shows (some of?) Ciresons events, and not those raised by e.g. Kendo controls or window / document.

    Which Kendo events have you found useful @Tom_Hendricks? Also, what / where is the new "toast notification" you mentioned?
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    Great suggestion for outputting the events to the console, @Konstantin_Slavin-Bo!

    To answer your questions and keep adding to our list here, I have found myself overriding the Open, Close, Select, and Change events of the userpicker controls.  The userpickers are a Kendo UI AutoComplete control.  The link here references the Events and Methods, among other things that you would want to get to know before/while diving in to overriding these events.  Have a look at this guide, because it is full of useful information, such as how programmatic changes to the control do not trigger a change event as you might expect--you must do so manually, in your code.

    I would also say that unless you have a good reason, do not do this.  It is very tricky to manage the timing, especially if you are including the original change event along with your own, for example, and there are no guarantees that a future portal update won't break your code. 

    To refer to one of these controls in your JS code, I have found code such as this to work best/most reliably.  Assuming you want to target the Affected User, which is actually called "RequestedWorkItem" in the view model (that is the name of the relationship target in the MP, after all):

    var ctrl = $('input[name="RequestedWorkItem"]').data('kendoAutoComplete');

    Now you can bind your own events, such as $(ctrl).bind('change', myChangeEvent)

    So in my case, I captured the original change event for later use, unbound it, and bound my own change event, which calls the original one at a certain point, because I still want all the actions Cireson intended to occur, just not until after I run mine.  Capturing the change event (which you must do before binding your own) would look like:

    var originalChangeEvent =  ctrl._events.change[0];
    // Not shown: Make sure there is at least/only one change event and/or that [0] is the one you want!!!

    In the case of the Open and Close events, I simply wanted my own events to fire after the original and/or there was none bound already, so it was not necessary to capture an existing event.  I only had to add $(ctrl).bind('Open', myOpenEvent), for example.

    Why did I override these?  Context might be helpful.  For open and close, (which occur when the list appears or disappears below the input box, respectively), I wanted to clear or show (again, respectively) a toast notification showing details about the affected user, such as if they are a VIP, what computer(s) they are primary users of and what OS those run.  And that last bit is why I overrode the Change event:  I need to perform an ajax call to get that info and add it to the RequestedWorkItem object, as part of the change.  In my custom change event, I also handle situations such as the user clearing out the box, which causes me to have to handle the values of those properties I added, to keep certain functions from getting confused.

    This post is already quite long, but you asked about the toast notifications.  My post above was referring to the ones that Cireson added in v8, not my own.  They are Kendo UI Notification widgets.  They also look TERRIBLE with mine, and do not respect my user info toasts or error messages, so you get a lot of overlapping toasts that nobody can read.  I am not casting blame here--Cireson used another tool in the same toolbox they have been using since forever ago, and should not be expected to compensate for mine--but I also cannot allow my UI to continue looking this way.  So I had to capture these and redirect them into my toasts (different library) that know how to share space on the screen, etc.  This was not as clean as binding to an event but the toasts do not seem to exist in the DOM until it is time for them to be displayed, so there is nothing to bind to.  I would be thrilled if someone could show me that I am wrong about this and how I can accomplish this without a mutation obsever.

    My solution here was to create a mutation observer that looks for the container that these notifications get added to, near the end of the DOM.  It observes document.body and looks for $('.k-animation-container') but it is very important to note that other types of controls add elements to this too (such as the dropdown list of an autocomplete...).  So inside of the mutation observer it only runs against children that correspond to a notification, like this:

    var notifyDiv = $('.k-animation-container');

    if (notifyDiv && notifyDiv.length > 0) {
        notifyDiv.children('div.k-notification').each(function () {
            $(this).hide();
            $(this).children().each(function () {
                var kendoToast = this;
                // Get the message
                var kendoMsg = kendoToast.innerText;
                // Get the message type
                var kendoTypes = ['info','success','warning','error'];
                // Create a toast matching the type of notification generated
                $(kendoTypes).each(function () {
                    if ($(kendoToast).hasClass(this)) {
                        // Do stuff here to forward the message contained within this notification to a different toast object
                        // Pseudo-code:
                        myToast[this]({
                            message: kendoMessage
                        });
                    }
                    // Remove the DOM element.  kendo will do this eventually on its own, but not fast enough to hide it
                    $(kendoToast).remove();
                });
        });
    }

    It works flawlessly and efficiently so far, but it still feels like a bit of a hack.

    I hope that all of this is helpful!
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    I love this suggestion, @john_doyle!  It is simple, easy to implement, and has just the right amount of "I can't believe I didn't think of that on my own."  :)
  • Konstantin_Slavin-BoKonstantin_Slavin-Bo Customer Ninja IT Monkey ✭✭✭✭
    @john_doyle
    That's an awesome idea! As Tom said; I can't believe I didn't think of that myself! I have even seen the option in Admin Settings, and though to my self numerous times, that there must be something useful / interesting I can use this for, but I couldn't come up with anything. But this of course is an obvious use for those fields, and I'm gonna try this out in the coming time. Thanks!
  • Adrian_PaechAdrian_Paech Customer Advanced IT Monkey ✭✭✭
    edited September 2017
    @john_doyle thanks for the tip.
    Unfortunately the footer still seems to load quite a while before the page is entirely loaded, so it still prevents me from adding triggers on page widgets etc.
    Does anyone else have any other ideas about how we can run something after the page is entirely loaded?
    E.g.: Even if we have to use a mutation observer, what is something that we could check which loads right at the end of the load process?
  • Morten_MeislerMorten_Meisler Premier Partner Advanced IT Monkey ✭✭✭
    @john_doyle thanks for the tip.
    Unfortunately the footer still seems to load quite a while before the page is entirely loaded, so it still prevents me from adding triggers on page widgets etc.
    Does anyone else have any other ideas about how we can run something after the page is entirely loaded?
    E.g.: Even if we have to use a mutation observer, what is something that we could check which loads right at the end of the load process?


    I can confirm this. Trying to replace a link on an RO, but the DOM elements seems to only be fully loaded/populated after a while. So I am still using the delay option.

    Example:

    $('span[data-request="057cf2e9-85f6-0a35-b9a0-8bf5ee5dcf94"]').attr('data-request-url','http://google.com')

    I tried making a load event on this element and others, but doesn't work.

    So even though custom.js/custom.css is renderered at last in the viewmodel, I figure that the async calls complicate matters. So there should be somekind of callback to an event publish when the last element is loaded (whatever that is :))

    I think many would love one final event to subscribe to.


     

  • Morten_MeislerMorten_Meisler Premier Partner Advanced IT Monkey ✭✭✭
    edited September 2017
  • Tom_HendricksTom_Hendricks Customer Super IT Monkey ✭✭✭✭✭
    I did, a while back.  :)  Everyone else get over there, too!
Sign In or Register to comment.