Future parser in parameterised menu

22 views
Skip to first unread message

Aditya Godara

unread,
Mar 18, 2015, 3:17:19 PM3/18/15
to lif...@googlegroups.com
Hi All,

First of all I would like to say that I am delighted to be part of lift community. I have finally decided to learn lift web after many attempts. In this ongoing attempt, I am developing a demo catalog app (code) in Liftweb 3.0-M3 and using slick 3.0.0-RC1 for database access. 

As in most catalog websites, there is a menu for categories, using parameterised menu. 

val menu = Menu.param[Category]("Category", Loc.LinkText(c => Text(c.urlKey)), Catalog.categoryByUrlKey _, _.urlKey) /

    "category" >> Loc.Template(() => Templates("category" :: "list" :: Nil).openOr(NodeSeq.Empty)) >> Loc.Title(c => Text(c.name))


I am trying to find a solution so that I can use string => Future[Box[T]] for parser parameter, i.e. Catalog.categoryByUrlKey becomes a string => Future[Box[Category]].

Reason, starting from versions 3.0 of slick all queries return futures, and to use query results in Menu I must Await results.

The code is in slick-dal-impl branch.


Thank You


Aditya

Diego Medina

unread,
Mar 18, 2015, 3:27:47 PM3/18/15
to Lift
Hi Aditya,

Great that you are getting into Lift!
About the issue you are having, while the idea of using Future[T] sounds very good so youdo async I/O, etc, there is also the reality that you have an actual user waiting to see his/her information.

the menu needs to know right away what the item is, so that you can display the information about it on the page, if we were to have a Future[T] in there, what do we give the user? Some people think a loading animation is the way to go, I would say that you need to make your database return the information as soon as possible, because seeing a loading animation is just as bad, if not worse, than a slow page load.

In short, use Await to get the type, and while reading articles online may give you the idea that this path isn't the best, remember that the end goal on your web app is to server the data as fast as you can.
Futures are great for tasks where the user can wait or doesn't care how long it takes.

Thanks

Diego




--
--
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+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Diego Medina
Lift/Scala consultant
di...@fmpwizard.com
http://fmpwizard.telegr.am

Aditya Godara

unread,
Mar 18, 2015, 3:54:09 PM3/18/15
to lif...@googlegroups.com
Hi Diego,

Thank you for quick response. I suppose I was relating it to parallel evaluation of snippets, where parallel snippets completed before final render are sent with response.

Antonio Salazar Cardozo

unread,
Mar 18, 2015, 4:06:51 PM3/18/15
to lif...@googlegroups.com
So, for what it's worth, I think you can do this, sort of, but the type of the parameter will
have to be Box[Future[Box[T]]], so the menu will be a Menu.param[Future[Box[Category]].
In your snippets, you can ignore the outer Box, but the biggest issue is that you won't know
if you should be 404ing until after the Future is resolved :/

You can always define:

  def futureParser(finder: (String)=>Future[Box[T]]): (String)=>Box[T] = {
    { id: String =>
      Await.result(finder(id))...
    }
  }

And then go:

  Menu.param[Category]("Category", …, futureParser(Catalog.categoryByUrlKey _), _.urlKey)

Or something like that.
Thanks,
Antonio
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.

Aditya Godara

unread,
Mar 19, 2015, 2:20:37 PM3/19/15
to lif...@googlegroups.com
Hi Antonio,

Thank you for your solution, ill try it. A use case might be returning other useful content instead of 404. e.g. parser could always resolve to an incomplete Box[Future[Category]], and Future[Category] this will be current loc param(am I right here). If current loc resolves to Failure in a snippet, render something else such suggested categories etc (some might argue that its better to return custom 404).

However, awaiting in parser function isn't; a bigger problem, as its loading only one row/model from db. My concern was rendering Category navigation as may take longer, because of loading many categories from db. So I am not using menu builder for that. Good thing, I could do something like

def render = "#categories-nav *" #> renderFutureCategory()


private def renderFutureCategory(): Future[Seq[NodeSeq]] 


in my snippet to render navigation asynchronously. Which is magically behaving like parallel snippet execution.


Thanks Again.

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

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages