Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Targets creation #41

Closed
savroff opened this Issue Jan 5, 2018 · 12 comments

Comments

Projects
None yet
5 participants
@savroff
Copy link

commented Jan 5, 2018

This time I will try to act smarter and ask before write code 馃槀

Sometimes I need to create a DOM elements, that Stimulus controller should controller after.
For example in this interface, when I create a new item, I need a way to add it to DOM.
vr9svsvjo7

Right now I need to write this

    // create tag element
    const item = document.createElement('div')
    item.setAttribute('data-title', 'aa')
    item.setAttribute('data-id', 123)
    item.setAttribute('data-target', 'categories.selected_item')
    item.setAttribute('data-action', 'click->categories#removeItem')
    item.setAttribute('class', 'categories--selected-item')
    item.innerHTML = 'aa'

    this.targets.find('selected_items').appendChild(item)

Can we present some sort of function to simply create new dom elements inside. Like:

// element can be a 'div' by default
const target = this.targets.create('selected_item', { 
  element: 'div', 
  data: {}, 
  htmlOptions: { class: 'categories--selected-item' }, 
  innerHTML: '' 
})
this.targets.find('selected_items').appendChild(target)

Probably we can just create a simple standard way to adding mix-ins to controllers.
This case we can keep things like that outside of Stimulus

@mdesantis

This comment has been minimized.

Copy link

commented Jan 6, 2018

What about using template tag? https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template

@savroff savroff closed this Jan 6, 2018

@savroff

This comment has been minimized.

Copy link
Author

commented Jan 6, 2018

@mdesantis thank you! 馃帀

@javan

This comment has been minimized.

Copy link
Contributor

commented Jan 6, 2018

You can access a controller's own identifier with this.identifier. So you can avoid hard coding and repeating it by doing:

item.setAttribute('data-target', `${this.identifier}.selected_item`)
item.setAttribute('data-action', `click->${this.identifier}#removeItem`)

Instead of:

 item.setAttribute('data-target', 'categories.selected_item')
 item.setAttribute('data-action', 'click->categories#removeItem')
@savroff

This comment has been minimized.

Copy link
Author

commented Jan 6, 2018

@javan what I actually did.
I created own Conrollerclass with wrapping original Stimulus one and added functions there.

Can we think of a simple way to do a mix-in? Like for example in Vue

@savroff

This comment has been minimized.

Copy link
Author

commented Jan 6, 2018

@mdesantis one problem with templates, seems like they not supported in IE 馃挬
But a lot of our users still use last version of IE

@mdesantis

This comment has been minimized.

Copy link

commented Jan 6, 2018

Yes, but there are many working polyfills in the wild :-)

@mdesantis

This comment has been minimized.

Copy link

commented Jan 6, 2018

Anyway, I feel the needing of managing potentially existing HTML components, in a library like this one. Something that solves the requirement "How to display a new incoming message on my instant messaging app?"

@savroff

This comment has been minimized.

Copy link
Author

commented Jan 6, 2018

Agree, this can be placed in examples and in the handbook. Seems like I closed this issue too early :)

@mdesantis idea with templates is really nice, this case you can keep HTML related things in Rails view, but we need to include polyfill in a framework (could increase library size a little).

Or we can create new elements and insert them like I showed, plus wrap it in nicer helper. But I see a downside here, that new element markup fully created in the .js file.

Or introduce data-template.
@javan what you think about all these?

@savroff savroff reopened this Jan 6, 2018

@rainerborene

This comment has been minimized.

Copy link

commented Jan 7, 2018

Another alternative would be to provide facilities for cloning existing elements, so you can change any attribute you want before appending to the DOM. That way you don't have to deal with template strings (or rendering engine?!) which I'm not in favor of adding an unnecessary layer of complexity. I was thinking of data-bind-* attributes which allows you to expose an interface to your JS instead.

<ul class="tasks">
  <li data-controller="task_item" data-bind-text="task_item.name">Todo item</li>
</ul>

Or you could define this interface in your controller to avoid duplicated code if you're not using <template>:

interface: {
  name: '@text' // xpath-like expressions
}

Then somewhere in your JS you would do something like this:

this.clone().feed({ name: "New todo item" }).appendTo(this.element.parentNode)

Just my 2 cents.

+1 for <template> and pollyfills.

@javan

This comment has been minimized.

Copy link
Contributor

commented Jan 8, 2018

Remember:

Stimulus is a JavaScript framework with modest ambitions. It doesn't seek to take over your entire front-end鈥攊n fact, it's not concerned with rendering HTML at all.

We don't plan to add our own way to do rendering, and there are a number of great options for you to chose from. I'd start small with document.createElement() or element.cloneNode(), and then reach for a templating library if needed. I'm a fan of hyperHTML and good ol' EJS.

@javan javan closed this Jan 8, 2018

@pacMakaveli

This comment has been minimized.

Copy link

commented Jan 11, 2018

@savroff on top of using template, you can also combine the template functionality with lodash's template and create this:

javascript: https://github.com/games-directory/games.directory/blob/v2.0-beta1/app/javascript/packs/controllers/identity_verification_process_controller.js

view: https://github.com/games-directory/games.directory/blob/v2.0-beta1/app/views/users/form/verification/_search.erb

The only downside is, at least for me, that you have to use .erb.

TL;DR

You can create a simple HTML template enclosed by a script tag which gets ignored when viewing the page because of type='text/template'

<div id='responseBody' class='row align-top'></div>

<script type='text/template' id='responseBodyTemplate'>

  <div class='cell-sm-12 -margin-top_2'>
    
    {{ _.forEach(identities, (identity) => { }}

      <h3 class='-line-reset'>{{= identity.name }}</h3>
      <p class='-line-reset -margin-top_4'>
        About: 
        <span class='-weight-regular'>{{= identity.about }}</span>
      </p>

    {{ }) }}

  </div>  <!-- cell-sm-12 -->

</script>
// Find the Template
const container = document.getElementById('responseBodyTemplate');

// Tell lodash to grab the contents of the Template
const template  = _.template(container.innerHTML);

// Magic happens
// 'parse' the template and pass the required variables
document.getElementById('responseBody').innerHTML = template({
  identities: [{ name: 'Foo', about: 'Bar' }]
});
@savroff

This comment has been minimized.

Copy link
Author

commented Jan 11, 2018

@pacMakaveli thanks!
I personally like keep markup outside from js files. 馃槏 We similar approach to this one and keep HTML in erb sounds really reasanoble in my case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can鈥檛 perform that action at this time.