Dropdown menu item with link only defined after user login

43 views
Skip to first unread message

Colin Bester

unread,
May 3, 2018, 8:06:34 AM5/3/18
to Lift
I have a menu child item that is only displayed when a user is logged in. If logged in and user clicks this item I want to open a new page and display user's eula that they agreed to via rest endpoint. Endpoint requires user id which is stored in session var on login.

My solution works in Safari and Chrome but fails in IE due to nest anchors (they only nest in IE).

My solution was:

 val eulaLoc = Loc("UserEula", "userEula" :: Nil, eulaLink("menu.eula"), loggedIn)

where

  def eulaLink(dflt: String): NodeSeq = {
    val eula
= for {
      user
<- UserService.currentUser
      id
<- user._id
      dest
= s"api/eula/${id}"
   
} yield <a href={dest} target="_blank">{S.loc(dflt, Text(dflt))}</a>


    eula match
{
     
case Full(ref) => ref
     
case _         => NodeSeq.Empty
   
}
 
}

I have tried using text for name and ExtLoc for Link but this only instantiates ExtLoc once and not per session - which I understand purpose of.

I have tried calling my own new Link to create a null link or simple span element and not an anchor element to no avail

def span() = new Loc.Link[Unit](Nil, false) {
   
override def createLink(value: Unit): Box[NodeSeq] = Full(<span></span>)
 
}
 
val eulaLoc
= Loc("UserEula", span(), eulaLink("menu.eula"), loggedIn)

What I have: <li><a href=""></a><a href="api/eula/54d4cf342f1e3fe899f6c6e5" target="_blank">EULA</a></li>

What I want: <li><a href="api/eula/54d4cf342f1e3fe899f6c6e5" target="_blank">EULA</a></li>

Appreciate suggestions.

Matt Farmer

unread,
May 16, 2018, 10:36:29 PM5/16/18
to Lift
Hey Colin, sorry this slipped through the cracks.

I'm not entirely sure I understand why the behavior is different in Chrome/Safari and IE. Are you producing the same tags in both browsers and they're behaving differently or are there different tags being produced in each browser?

Also what version of IE are we talking about?

--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

---
You received this message because you are subscribed to the Google Groups "Lift" group.
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Colin Bester

unread,
May 19, 2018, 11:49:38 AM5/19/18
to Lift
On Chrome and Safari (on MAC) the generated code looks like:
 
<li><a href=""></a><a href="api/eula/54d4cf342f1e3fe899f6c6e5" target="_blank">EULA</a></li>

While in IE it looks like (nested anchor tag)

<li><a href=""><a href="api/eula/54d4cf342f1e3fe899f6c6e5" target="_blank">EULA</a></a></li>

I am not sure which IE I used but believe it was latest Microsoft Edge browser, I don't recall if I tested with IE 11 as well.

My preference would be to only have one anchor generated but don't see how this can be done due to requiring dynamic api id after user logs in.

~C
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+u...@googlegroups.com.

Matt Farmer

unread,
May 19, 2018, 3:57:18 PM5/19/18
to lif...@googlegroups.com
Oh, I understand what you're seeing now. Yeah, it should be possible to avoid having two anchor tags.

I suspect what is happening is that Chrome and Safari are just smart enough to close the first anchor tag automatically when they see the second one begin. So you're seeing a different result in the output even though the HTML coming over the wire has nested anchor tags.

In the past I've just used Menu objects in my sitemap and some custom CSS bindings to hide/show things when I needed this behavior.

If you can create a sample project that demonstrates the issue, though, I'm happy to see if I can create a solution. It's kind of hard to work on it without some code in front of me though. :/

Colin Bester

unread,
May 19, 2018, 6:52:36 PM5/19/18
to Lift
I created sample project at https://github.com/colinbes/lift-3/tree/dyn-menu in branch dyn-menu that demonstrates what I am trying to accomplish and issue mentioned of nested anchors.

In example, I am simply using logged in users email which is saved in sessionvar and appending to endpoint url /api/eula/<user email>.

Hope this makes sense.

Colin Bester

unread,
Jun 6, 2018, 3:52:11 PM6/6/18
to Lift
Was wondering if you had a chance to look at this?

Matt Farmer

unread,
Jun 6, 2018, 9:53:29 PM6/6/18
to lif...@googlegroups.com
Ah, I'm sorry Colin - somehow the email got archived in my inbox and I lost track of it. I'll take a look at it now.

Matt Farmer

unread,
Jun 6, 2018, 10:33:48 PM6/6/18
to lif...@googlegroups.com
I've  been unable to get the project to build so far... seeing a bunch of:

error: scala.reflect.internal.MissingRequirementError: object java.lang.Object in compiler mirror not found.
at scala.reflect.internal.MissingRequirementError$.signal(MissingRequirementError.scala:17)
at scala.reflect.internal.MissingRequirementError$.notFound(MissingRequirementError.scala:18)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:53)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:45)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:45)
at scala.reflect.internal.Mirrors$RootsBase.getModuleOrClass(Mirrors.scala:66)
at scala.reflect.internal.Mirrors$RootsBase.getClassByName(Mirrors.scala:102)

Are you seeing this on your end?

Colin Bester

unread,
Jun 7, 2018, 7:00:06 AM6/7/18
to Lift


It did build/compile and run on my side.

Just wanted to check that you did pull branch dyn-menu?

Also I used scala-ide (eclipse) and build against scala 2.11.x and java 8.

I will re-pull from repository and try build this afternoon and let you know.

~C

Colin Bester

unread,
Jun 7, 2018, 12:41:48 PM6/7/18
to Lift
I have just pulled dyn-menu from github, compiled mystyles.less to mystyles.css and executed mvn jetty:run and project ran as expected.

Using:
  • macos
  • maven 3.5.0
  • java 1.8.0_151

Matt Farmer

unread,
Jun 7, 2018, 12:59:07 PM6/7/18
to lif...@googlegroups.com
Alright, I'll try this again this afternoon and see what I can figure out.

--

Matt Farmer

unread,
Jun 7, 2018, 9:12:04 PM6/7/18
to lif...@googlegroups.com
Hey Colin,

The problem I mentioned above was in my environment. I think I see your problems.

The first is the reason you're getting the nested anchor tags. The entire Loc gets wrapped in an anchor by the framework when the menu is generated, so when you create a custom anchor tag just for the user that ends up getting nested inside of it, and  you witness the weird behavior your saw in various browsers.

The second is that the way you're constructing the locs isn't the easiest to work with. I'd highly recommend using param menus to construct your locs for your app. You can see an example of me using param locs here in the AnchorTab project. I can even provide functions to automatically resolve email addresses in the URL to User objects in your code. (Or IDs to Tab objects in the code I think above.) You can see how I pull things into the final sitemap in my sitemap setup function. I think changing the way you're using the APIs a bit will make reasoning about this problem a bit easier.

Please let me know if this isn't helpful or if you have other questions!

Colin Bester

unread,
Jun 8, 2018, 11:41:08 AM6/8/18
to Lift
Thanks Matt, much appreciated. Looking into it now and hoping that it will continue to work with FoBo library and it's menu builder due to bootstrap use.

I am battling to get my head around Menu.param but haven't been at it for long.

In particular (and using your code as example) I can't example example source to work.

object Invoice {
  val menu
= Menu.param[String](
   
"Invoice",
   
"Invoice",
    s
=> Full(s),
    s
=> s
 
) / "manager" / "invoice" / * >>
 
TemplateBox(() => Templates("manager" :: "invoice" :: Nil)) >>
 
Authentication.ifLoggedIn
}

I keep getting error "*" not found and not sure why.

~C

Matt Farmer

unread,
Jun 9, 2018, 5:45:22 PM6/9/18
to lif...@googlegroups.com
What URL are you trying to access in your browser when you get that error?

Matt Farmer

unread,
Jun 9, 2018, 5:45:39 PM6/9/18
to lif...@googlegroups.com
Or, are you getting a compiler error?

Colin Bester

unread,
Jun 9, 2018, 5:47:48 PM6/9/18
to lif...@googlegroups.com
Compiler error. 

Sent from my iPhone
You received this message because you are subscribed to a topic in the Google Groups "Lift" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/liftweb/qP5JnDLbLn4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to liftweb+u...@googlegroups.com.

Colin Bester

unread,
Jun 9, 2018, 5:57:58 PM6/9/18
to Lift
Matt, so it seems to me that Menu.param(s) is meant more for tailor menu items to current url and passed parameters - is this correct?

In my case I am purely looking to have menu item with redirect to specific endpoint based on logged user id, user id is not in url but is in session var - for now I am using using simple static menu and then use LiftRules.DispatchPF to 'catch' endpoint and dynamically process end point xxxxx (e.g. /usereula/xxxxxx)

I appreciate your help but also don't want to waste your time but do want to dig a little more into Menu.param but am battling to find documentation.

Matt Farmer

unread,
Jun 10, 2018, 9:13:08 AM6/10/18
to lif...@googlegroups.com
Oh. I thought I saw in your example that the user id was a part of the eula component. Menu.i would have worked if you didn’t need params in your url.

I want to link you to the cookbook page for menus but the css seems to be busted. Starting a new thread..
--

Colin Bester

unread,
Jun 10, 2018, 9:23:11 AM6/10/18
to Lift
To make sure we are on same page.

I am looking to create (in menu) anchor elem such as <a href="somewhere/<userid>>EULA</a> where userid is retrieved from session var. The url to current page being displayed could be something like http://mywebapp.com/landing - ie., no userid info in page url. This menu item is to be available in top nav bar under "user" menu across all pages.

Matt Farmer

unread,
Jun 12, 2018, 8:22:46 PM6/12/18
to lif...@googlegroups.com
This may be a silly question, but why do you need the user id to be part of the url if it's stored in a session var?

Colin Bester

unread,
Jun 13, 2018, 7:51:28 AM6/13/18
to Lift
Not silly at all, quite valid. As I am calling an external rest server endpoint http://server/endpoint/id/<id> as a menu entry (menu click user->eula) I thought it clean and easy (ha!) to simply have a menu item with <a href="http://someserver/user/eula/id/83838ae33839a0>EULA</a> that's available after the user has logged in. On login, user safe to share user information is stored in sessionvar.

I could not get this to work so ended up have menu set to /userEula and then using dispatchPF to 'catch' userEula:Nil, pull info from sessionvar and then redirect to required url which is ugly but functional.

Colin Bester

unread,
Jun 13, 2018, 7:52:28 AM6/13/18
to Lift
Thanks for link!


On Sunday, June 10, 2018 at 8:13:08 AM UTC-5, Matt Farmer wrote:

Matt Farmer

unread,
Jun 16, 2018, 1:20:16 PM6/16/18
to lif...@googlegroups.com
I understand your use case now.

If I were to write that using a Menu I would probably do something like the following:

val referralMenu = Menu.i[String]("eula") / "eula" >>
  EarlyResponse(eulaRedirect _)

def eulaRedirect: Box[LiftResponse] = {
  {
    for {
      userId <- userIdSessionVar.currentValue
    } yield {
      RedirectResponse(s"/api/$userId")
    }
  } or {
    Empty
  }
}

I haven't checked to see if that compiles, but I think it gets as the gist of what you're going for. When any user visits "/eula" on a site with this Menu in the SiteMap it'll pull the userId from the SessionVar and redirect to another URL. If for some reason the user id isn't defined it'll try to render eula.html like a normal path would (that's what the or condition here does). You could change that to redirect to a different URL, return a 404, etc.

Colin Bester

unread,
Jun 16, 2018, 2:19:28 PM6/16/18
to Lift
Ah, that makes so much sense now. I saw EarlyResponse but didn't quite see it being used like this.

Thanks so much!
Reply all
Reply to author
Forward
0 new messages