Search code examples
scalaweb-applicationslift

Cannot access the parameter of a Menu.param from a Lift Snippet


I'm trying to extract the parameter from a Lift Menu.param within a snippet so that I can use it to create a named Comet. However, I get a NullPointerException when I try to pass the parameter to the snippet using SnippetDisptach in my Boot.scala, as suggested here: http://comments.gmane.org/gmane.comp.web.lift/44299

I've created the Menu item as follows:

object AnItemPage {
// create a parameterized page
  def menu = Menu.param[Item]("Item", "Item",
                                s => fetchItem(s), item => item._id.toString) / "item"

  private def fetchItem(s:String) : Box[Item] = synchronized {
          ItemDAO.findById(ObjectId.massageToObjectId(s)) 
  }

}

I've added the menu to SiteMap. I've also created a Snippet which I would like to pick up the Item parameter. (I'm using fmpwizard's InsertNamedComet library here):

 class AddCometItemPage(boxedItem: Box[Item]) extends InsertNamedComet with DispatchSnippet{
     val item : Item = boxedItem.openOr(null)
     override lazy val name= "comet_item_" + item._id.toString
     override lazy val cometClass= "UserItemCometActor"

     def dispatch = null
    }

My next step is to crate an instance of this class as demonstrated by David Pollak here: http://comments.gmane.org/gmane.comp.web.lift/44299

This is what I have added to my Boot.scala:

LiftRules.snippetDispatch.append {
  case "item_page" => new AddCometItemPage(AnItemPage.menu.currentValue)
}

My item.html references this snippet:

 <div class="lift:item_page">

I get the following null pointer exception when I compile and run this:

Exception occurred while processing /item/5114eb4044ae953cf863b786

Message: java.lang.NullPointerException
net.liftweb.sitemap.Loc$class.siteMap(Loc.scala:147)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.siteMap(Menu.scala:170)
net.liftweb.sitemap.Loc$class.allParams(Loc.scala:123)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.allParams(Menu.scala:170)
net.liftweb.sitemap.Loc$class.net$liftweb$sitemap$Loc$$staticValue(Loc.scala:87)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.net$liftweb$sitemap$Loc$$staticValue(Menu.scala:170)
net.liftweb.sitemap.Loc$$anonfun$paramValue$2.apply(Loc.scala:85)
net.liftweb.sitemap.Loc$$anonfun$paramValue$2.apply(Loc.scala:85)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.sitemap.Loc$class.paramValue(Loc.scala:85)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.paramValue(Menu.scala:170)
net.liftweb.sitemap.Loc$$anonfun$currentValue$3.apply(Loc.scala:114)
net.liftweb.sitemap.Loc$$anonfun$currentValue$3.apply(Loc.scala:114)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.sitemap.Loc$class.currentValue(Loc.scala:114)
net.liftweb.sitemap.Menu$ParamMenuable$$anon$9.currentValue(Menu.scala:170)
bootstrap.liftweb.Boot$$anonfun$lift$8.apply(Boot.scala:107)
bootstrap.liftweb.Boot$$anonfun$lift$8.apply(Boot.scala:106)
net.liftweb.util.NamedPF$$anonfun$applyBox$1.apply(NamedPartialFunction.scala:97)
net.liftweb.util.NamedPF$$anonfun$applyBox$1.apply(NamedPartialFunction.scala:97)
net.liftweb.common.Full.map(Box.scala:553)
net.liftweb.util.NamedPF$.applyBox(NamedPartialFunction.scala:97)
net.liftweb.http.LiftRules.snippet(LiftRules.scala:711)
net.liftweb.http.LiftSession$$anonfun$net$liftweb$http$LiftSession$$findSnippetInstance$1.apply(LiftSession.scala:1506)
net.liftweb.http.LiftSession$$anonfun$net$liftweb$http$LiftSession$$findSnippetInstance$1.apply(LiftSession.scala:1506)
net.liftweb.common.EmptyBox.or(Box.scala:646)
net.liftweb.http.LiftSession.net$liftweb$http$LiftSession$$findSnippetInstance(LiftSession.scala:1505)
net.liftweb.http.LiftSession$$anonfun$locateAndCacheSnippet$1$1$$anonfun$apply$88.apply(LiftSession.scala:1670)
net.liftweb.http.LiftSession$$anonfun$locateAndCacheSnippet$1$1$$anonfun$apply$88.apply(LiftSession.scala:1669)

Has anybody any idea where I'm going wrong? I've not been able to find a lot of information on Menu.param.

Thank you very much for your help.

f


Solution

  • I have never tried what you are doing, so I am not sure the best way to accomplish it. The way you are using the Loc Param, you are extracting a variable from a URL pattern. In your case, http://server/item/ITEMID where ITEMID is the string representation of an Item, and which is the value that gets passed to the fetchItem function. The function call will not have a value if you just arbitrarily call it, and from what I can see you are requesting a value that is not initialized.

    I would think there are two possible solutions. The first would be to use S.location instead of AnItemPage.menu.currentValue. It will return a Box[Loc[Any]] representing the Loc that is currently being accessed (with the parameters set). You can use that Loc to retrive currentValue and set your parameter.

    The other option would be to instantiate the actor in your snippet. Something like this:

    item.html

       <div data-lift="AnItemPage">
         <div id="mycomet"></div>
       </div>
    

    And then in your AnItemPage snippet, something like this:

    class AnItemPage(item: Item) {
      def render = "#mycomet" #> new AddCometItemPage(item).render 
    }
    

    I haven't tested either of those, so they'll probably need some tweaking. Hopefully it will give you a general idea.