LinkedInAttic / hopscotch

A framework to make it easy for developers to add product tours to their pages.
Apache License 2.0
4.2k stars 666 forks source link

How to set up onNext function, when using a database to set up the steps properties? #371

Closed karapapas closed 5 years ago

karapapas commented 5 years ago

Hello, in my project, I dynamically create tours and steps from values retrieved from a database. So far I wasn't able to assign a function, i.e. to the onNext property. The problem is that the function is retrieved as a string from the database. So I end up with something like the following, which I guess is no surprise that it doesn't work.

content: "Test Content..." onNext: "function(){alert('help!');}" placement: "top"

sneakyfildy commented 5 years ago

Hey. http://linkedin.github.io/hopscotch/#defining-callbacks

In short, you would register those helpers and add them into a tour definition, either before launching a tour or creating this tour definition after receiving it from a backend. I personally have an additional routine of "processing" all tours after I get them.

karapapas commented 5 years ago

I solved this by writing to the database only the body of the function, and by assigning the eval of the value to the onNext property. Thank you anyway.

sneakyfildy commented 5 years ago

OMG, mate, it doesn't sound like a nice solution.

sneakyfildy commented 5 years ago

Check this out https://jsfiddle.net/cmk0ozaL/

When your application loads (or anytime before you start a tour), you register a "helper", it's just an id of some function

hopscotch.registerHelper("genericHelper", function() {
  alert("hello");
});

And then you put onNext: ["genericHelper"] inside your tour definition. You can have it in database or you can setup this dynamically (and have dynamic helpers names/quantity). In this case when "next" happens, the genericHelper function will be executed. Or you may have bunch of helpers executed (according to a manual).

Generally developers tend not to keep functions in database :) You may keep their names there. But define and setup them on client side.

karapapas commented 5 years ago

So, the "official" usage of a helper is one helper per function? Or could I still define dynamically the helper function?

Imagine the scenario where you'd need a function per db entry, well, one might say this beats the purpose of a function :D but since we are discussing this on hopscotch let me explain you what I am trying to do.

I guess I am not the first one who faced that problem, but some elements of the page are not available unless other actions first take place. For example a menu that appears after a mouseover event.

From the perspective of the one who builds the tour you would want to first trigger the mouseover and then show the step. Otherwise the step would show up in an irrelevant, to the element, position.

So, I thought a tailored function for each element, that I want to include in a step and is not visible by default, would be a good idea. Could you please tell me how you deal with that kind of elements?

Also, you said that my solution doesn't sound nice, is that for the case the user gets to set a function through an input, or is there any other drawback to this approach? Thank you for your time.

sneakyfildy commented 5 years ago

Okay. I will try to answer tomorrow :)

sneakyfildy commented 5 years ago

Alright you owe me now 25 minutes of my life :) https://jsfiddle.net/cmk0ozaL/7/

This is how I'd handle this (but do not use element IDs! use only relative selectors in real application)

1) You can define as many helpers as you want 2) These helpers may operate particular elements on a page or elements which are current (previous, any) step's target, or they may be inside that target 3) In your tour definition you may declare as many helpers as you want for each step and each event type (next/prev/end/start/...etc.) 4) You will want to run "onNext" step synchronously to make target of next step to get its size. Or do everything manually (call hopscotch.nextStep() manually after the animation ends, but you better do this on "onCTA" handler I presume)

"Also, you said that my solution doesn't sound nice, is that for the case the user gets to set a function through an input, or is there any other drawback to this approach?"

Storing a function in DB and then doing "eval" of its string version back again sounds crazy, honestly.

This sounds like you are making some kind of onboarding tours creation interface. People should not write code in browser inputs and get it stored somewhere, because this is "wild" code. All code should be written "normally", it should be reviewed, tested and stored in that way so the browser interprets it correctly. If you need an ability to add some custom logic inside tours NOT from source code I would suggest to develop some kind of "predefined" small pieces of such logic, like: "select a particular element", "hide/show/move subject element" and etc. So this tour developer will be able to choose and combine these pieces from your UI setting only for example elements selectors and other "static" inputs.

karapapas commented 5 years ago

Thank you for every minute you spent. 👍 I am going to study your answer and follow it to the best degree I can.

As, for the last thing you mention, in my case users don't get to define by any means the tour or any of the functions that these tours might need. I, and a couple of other fellow developers are going to be creating the tours.

The pre-defined pieces of logic makes sense and is a nice median solution but still if I wanted to automate the procedure of creating a tour a bit more I would probably have to move some information for this logic to the database, (i.e. a filed to hold as value the kind of action, mouseover etc.) (a second field for the second action, or even worse an intermediate table with step_ids and action_type_id, etc.) , but surely this is much better than having to store raw functions. The only drawback to this solution is that there is much more time between the abstract concept to the actual implementation.

sneakyfildy commented 5 years ago

much more time between the abstract concept to the actual implementation.

That's for sure. I'm at the moment trying to implement some kind of a "framework" to be able to setup onboarding tours across our UI. The whole week I've spent and the more I think about it, the less believe it can be automated :( There always appear a special freaking element which requires manual tweaking during the tour.

karapapas commented 5 years ago

Not only that, but I am sure that you have already thought, that this framework should offer some flexibility to the tours when changes are made to the page.

After spending a considerable amount of time in this case of "Tours" I am not sure if it was worth the time. Sure it's a great UI feature, but still most of the end users won't follow any guided steps, they will just pick up the phone and call the support :/

sneakyfildy commented 5 years ago

:D Yeah. Luckily, we do not have a phone!