" />
" />
"/>

Creating a reusable component with scalatags

358 Views Asked by At

I'd like to create a reusable component with scalatags like this one:

<div class="container">
  <button>Delete me</button>
  <div class="actual-content">
    ...
  </div> 
</div>

and I'd like to register an onclick listener to the button which deletes the whole div container when clicked.

I know that I can do something like this (with jQuery):

div(id:="myid")(
  button(onclick:={() => jQuery("#myid").remove()}(Delete me),
  div(...)
)

but the problem with this solution is that I'm generating this element automatically and getting the element by id is cumbersome because I'd have to generate unique ids.

Is there a better way? Is there a way to reference a 'myid' div from inside the div?

Thanks

2

There are 2 best solutions below

0
Nikita On BEST ANSWER

DOM Event callbacks (e.g. what you pass to onClick := ???) receive an instance of an Event as their first parameter. That event has a target property that contains the Node which the event was triggered on (in your case, that would be the button being clicked). That node has a parentNode property which refers to the parent node (element) of the target element. In your case the button's parentNode is your div, the node you want to remove. So you could provide this kind of callback to remove the div:

def clickHandler = (event: Event): Unit = {
  val myDiv = event.target.parentNode
  myDiv.parentNode.removeChild(myDiv)
}

However, you should know that this style of UI programming is very imperative and does not scale well to a bigger codebases. There are better ways to write frontend apps nowadays. For Scala.js for example there are a few libraries for managing DOM state:

There are more, these are just the ones that I remember right now.

0
Justin du Coeur On

I don't know of a simple answer for this one, I'm afraid, but here's some food for thought.

Personally, I wound up building a fairly elaborate framework, to deal with this issue among others. That introduces a notion that I wound up calling a GadgetRef, which encapsulates a Scala.Rx Var that references a Scalatags node, outside of the Scalatags tree, and gets set to the actual node when it is created.

So for example, this page defines an Input field in one place, sets it inside the Scalatags tree, and references it in other places.

That's a fairly elaborate framework, though, which isn't yet extracted into a separate library. So it's an idea, but not a silver-bullet answer to the problem...