Creating a reusable component with scalatags - scala.js

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

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:
Interfaces to React.js, a popular JS library (SRI or scalajs-react or react4s)
Scalatags-rx
Binding.scala
There are more, these are just the ones that I remember right now.

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...

Related

How to chain actions in purescript (or maybe defer action after rendering)

I'm learning Halogen at the moment but I have a hard time finding how to chain actions. Let's say I have a simple article list component. I also have an "add" button to create a new article to be edited in place in the list.
My approach would be to bind an AddArticle action to the onClick action of the button. In the handleAction function, I'd add a new empty article at the end of the article list model. Then I´d like to scroll to this newly created article. That's where I'm lost. To scroll to this newly created article, I'd have to have a ref to the new article, but it has not been redered yet. So here's the precise question:
How could I chain the two Effects of creating the new article (modify_ the state of the component) and the scrolling to this newly created element ?
In Halogen, whenever you modify the state of a component, it immediately re-renders. Halogen doesn't try to do anything clever with batching renders or anything like that, exactly so the behaviour is predictable and reliable for situations like this.
So here, you'd write it the way you described, pretty much:
handleAction = case _ of
AddArticle -> do
H.modify_ ?addArticle
ref <- H.getHTMLElementRef ?refName
H.liftEffect (?scrollTo ref)

Is there a Binding.scala way to append dom elements?

I would like to append a Binding node to another Binding node without re-rendering the parent node.
Is there a specific way how Binding.scala would handle this?
Bindings can be nested and composed, so in general it's not something you need to think about. A Binding[T] represents an object that is dynamically bound and will be recomputed when any upstream Binding's value changes.
Your question is a bit ambiguous so you may want to clarify or add a code example, but there is nothing extra you need to do to accomplish your goal. Look at the examples and also this section of the README:
https://github.com/ThoughtWorksInc/Binding.scala/blob/11.0.x/README.md#precise-data-binding
Also, I made a quick example of what I'm talking about here:
https://scalafiddle.io/sf/XZgtwHM/1
If you open up your browser console, you'll see that the method that renders out the parent node is only called the first time, but if you click the button more child elements will be appended without the parent node being affected. Inspect the HTML and pay attention to the id of the parent div, it is set up to increment the ID each time it gets rendered, and the id remains as "parent_1" the whole time.

How are regular DOM Elements mutable?

In the react docs, they claim:
ReactElements are not to be confused with DOM Elements. A ReactElement
is a light, stateless, immutable, virtual representation of a DOM
Element.
Does this imply that a regular DOM element can be mutated? And if so, can you give an example of how you can mutate a DOM element, but the same code applied to a ReactElement would not mutate it?
I think you may be reading too deep into that statement. I believe by the word immutable, the ReactJS documentation is saying that "this will not change between the moment we define to the moment that we use it".
I believe this comes from other frameworks such as old version of ASP.NET that changed the DOM object ID and changed other aspects of the DOM element created between the moment of creation and the moment of usage in the DOM.
However, this element can still be modified once it is actually rendered onto the DOM as a regular HTML element by jQuery. The beauty and downside to the DOM is that once anything is placed into the DOM, the validity of that data cannot be trusted. At the end of the day, it's just a document. Hopefully, that helps.
React components can be modified by props or state. State is internal to the component. Props are passed from the parent component. Any mutations on DOM should be made via props or state changes. Though some jQuery code works with React, it is highly discouraged.
After more research, I think this has to do with the virtual DOM.
The virtual DOM is all about "diffing" to find the differences (if any) among its ReactElements. If ReactElements could be mutated, then the virtual DOM wouldn't need to diff, as the element would just mutate itself and that would be the current state of the virtual DOM. But the virtual DOM wants to diff, so rather than updating the existing ReactElement, what happens is you pass the virtual DOM a new version of that ReactElement. And updating itself to the most recent version (sort of like git I guess), the virtual DOM then updates the real DOM with the most recent version of itself.
The full flow looks something like this (I think)
React takes your stateful ReactComponent (i.e. it can be mutated), turns it into a statless ReactElement(s) (i.e. if something changes, it issues a new ReactElement rather than updating the old one), which are used to create your virtual DOM. If state changes in your ReactComponent, a new version of the corresponding ReactElements are created and sent to the virtual DOM. The virtual DOM runs the new version of the ReactElements against the old, updates itself, and then updates the real DOM.
Traditionally, with regular DOM elements and regular DOM, there is no diff occurring (and so you don't have two versions of DOM elements, new and old, you just have the one single version that you are mutating as you go). So instead of sending a new version of the DOM element to be diffed, you just update the existing DOM element.
further reading:
React Elements vs React Components vs Component Backing Instances

ExtJS: Component VS Element VS other

I've been working with ExtJS for a good few months now, but still don't have a perfectly clear map of what's going on behind the scenes there. I'm just talking about the building blocks of the framework and their most basic functionality.
Ext.Component
Ext.Element
DOM.Element
DOM.Node (?)
CompositeElement (?)
Whatever else (?)
For each of the abovementioned I would like to know:
How to select: by ID, by class, via parent, find (OR children OR query OR select? WTF), siblings, ComponentQuery, DOM-query, CSS-query, etc..
How to manipulate in the tree: create, append, prepend, insert after this sibling, move to that parent, remove, destroy, etc..
How to manipulate on the screen: show, hide, fade, slide, move up, down, change size, etc..
How to identify related to each other: find DOM.Element knowing its Ext.Component, find Ext.Component knowing its DOM.Element, etc..
What is the dependency between them: what happens to the DOM.Element if its Ext.Component is hidden / destroyed / changed / moved, what happens to the Ext.Component if its Ext.Element is hidden / destroyed / changed / moved, etc.
I'm looking for a methodical and logically clear layout of how each is supposed to be used and is expected to behave. I am also hoping that the described functionality can be grouped in corresponding categories, e.g. would be nice to see complement traversing methods .up() and .down() next to each other, rather than alphabetically pages apart. Of course links and examples (which the official documentation lacks so badly) are also welcome!
You can find out a whole lot about the building blocks of ExtJS (known as Ext Core) from the manual for this: http://docs.sencha.com/core/manual/. I will try to add some knowledge and highlight some key points, but you should definitely read through that for a very informative overview.
Ext.Component
The building block for the OOP paradigm within ExtJS. Essentially, this is an Object that contains inherited functionality to serve as the basis for a specialized component that will be transformed by the framework into DOM elements that are shown as HTML.
The Sencha documentation is excellent for this. Here are a couple good places to start:
http://docs.sencha.com/extjs/4.2.1/#!/guide/layouts_and_containers
http://docs.sencha.com/extjs/4.2.1/#!/guide/components
Ext.Element vs DOM Element
As an JavaScript develop knows, a DOM element is just a JS object that represents a tag in the document's HTML. Essentially, Ext.Element is a wrapper object for a DOM element that allows for ExtJS to manipulate the object. Any DOM element on the page can be wrapped as an Ext.Element to allow for this additional functionality.
For example, take this HTML tag:
<div id="myDiv">My content</div>
You can access this using
var el = document.getElementById('myDiv')
and use the basic, built-in JavaScript DOM functionality on el. You could also access this using
var el = Ext.get('myDiv')
and have a whole additional set of functionality available to apply to that element using the ExtJS library
The Sencha docs are also excellent for this. See all the available functionality for Ext.Element here: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.dom.Element
Misc
You can get an Ext.Element from a component using the getEl() method:
var myComponent = Ext.create('Ext.Component', { html: 'my component' });
var el = myComponent.getEl();
You would rarely need to go the other way, to determine a component from a DOM element. There isn't much of a use case there unless you are really hacking something. A major reason for using a framework like ExtJS is to prevent needing to do something like this; if should develop entirely within the JavaScript, you should be able to avoid having a reference to a DOM element where you need to get its containing ExtJS component.
Niklas answered pretty well about how to select components and elements. The only things I would really add is that you can use up() and down() to select relative to a component. In this way, you should use itemId on components rather than the global identifier id (using id can cause difficult-to-debug errors if you are reusing components with the same ID).
Also, to add to Niklas's answer about showing/hiding components, the framework does indeed add some CSS to the component's element, depending on what the hideMode for the component is. Learn more about that property here: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.AbstractComponent-cfg-hideMode
An excellent way to learn more is to look through all of the examples that come packaged with the framework. Open the examples in your browser, then look through the code to find out how things are done. You will find it way easier to learn this way, rather than reading it on paper or a website. Nothing beats experience when it comes to learning something new.
How to select: by ID, by class, via parent, find (OR children OR query OR select? WTF), siblings, ComponentQuery, DOM-query, CSS-query, etc..
Ext.ComponentQuery.query("*") // get all
Ext.ComponentQuery.query("button") // all buttons
Ext.ComponentQuery.query("#myid") // all controls / components myid
Ext.ComponentQuery.query("#myid", rootelement) // all controls / components myid with rootelement
Ext.ComponentQuery.query("#myid,button") // all buttons or controls / components myid
How to manipulate in the tree: create, append, prepend, insert after this sibling, move to that parent, remove, destroy, etc..
Adding button to a View:
Ext.ComponentQuery.query("#viewId")[0].add(new Ext.Button({ text: 'test'}));
There is also insert, remove and so on depending on the control you are querying.
How to manipulate on the screen: show, hide, fade, slide, move up, down, change size, etc..
Ext.ComponentQuery.query("button").forEach(function(button){ button.hide(); }) // hide all buttons
There is also show, disable, enable and so on depending on the control you are querying.
How to identify related to each other: find DOM.Element knowing its Ext.Component, find Ext.Component knowing its DOM.Element, etc..
Finding Ext.Component knowing its Dom.Element is pretty easy, you just take the ID from the DOM element and use Ext.ComponentQuery.query("#id").
There is also Ext.select('#id') for getting the object from an ID.
With the element property you can get the DOM:
var dom = Ext.ComponentQuery.query("button")[0].element.dom // Getting the DOM from the first button
var dom2 = component.element.dom // does also work as long as component is a valid sencha touch component
What is the dependency between them: what happens to the DOM.Element if its Ext.Component is hidden / destroyed / changed / moved, what happens to the Ext.Component if its Ext.Element is hidden / destroyed / changed / moved, etc.
I think, I'm not sure, that if you call .hide for instance there will be some CSS applied to the DOM for example: display: none. Internally they can use some framework like jQuery for that or the old school version document.getElementById('id').css and so one. If you call .show, it may change to display: block or whatever type it was before(this could be saved in the Sencha Touch class).
I don't know what happens if the DOM element gets destroyed. Probably the element too and then the garbage collector has some work to do.
If there are any more questions / something was unclear or not enough, don't hesitate to ask.
An attempt to answer the question myself.
Since there is no TABLE markup support on this website, I put my answer in this shared Spreadsheet. Note the comments on mouse rollover.
It's just a pattern for now. It needs work to get more legible and complete. Feel free to comment, or ask me if you would like to edit it.

Does liftweb have iteration tags?

I was wondering, does Lift have an iteration tag (ex: for, foreach)?
When I was working with JSP, i could easily iterate a List, just with JSP, passing the object to the tag. Something like this, or like this.
I know it's not really the best example, but you do understand my intentions.
To sum up, does this exist with Lift, or if not, how would I manage to do such thing?
The last thing i want to do is hardcode html.
In short: No. Lift’s design strictly separates logic from design and as such forbids the use of generalised tags in the template markup.
Have a look at the view first article in order to see how lift can handle iterations.
An example from the article: Your markup:
<table>
<lift:show.users>
<tr>
<td><f:first_name>David</f:first_name></td>
<td><f:last_name>Pollak</f:last_name></td>
</tr>
</lift:show.users>
</table>
Your code:
class Show {
def users(xhtml: NodeSeq): NodeSeq =
Users.findAll.flatMap(user =>
bind("f", xhtml,
"first_name" -> user.firstName,
"last_name" -> user.nameName
)
)
}
Now, what lift does when it sees the tag <lift:show.users> is calling the corresponding method with the tag’s content as the argument. The tag will then be replaced by the return value of the users method.
The users method does the iteration over all Users and for each user, it binds the values of first and second name to the inner xhtml. All those iterations are then concatenated (through flatMap) and returned.
When I started with lift, I’d always found this approach a little too rigid; having a tiny loop here and there, how could that possibly hurt? But now that I know how easy it is to call and create your own snippets from the template code, I cannot imagine using anything like jsp anymore. It is weak in comparison and clutters your markup. And of course, you lose much of Scala’s power of validation.
Notes:
The reason the template tags are filled with content is for designing purposes. In this case the dummy tags and values are going to be replaced during the bind. The template designers can thus fill the tags with more or less meaningful content which allows the coder to better understand the semantics the designer had in mind.