1

Is there a way to listen the onclick event of #selectDate element, and while clicked, the item variable also get passed to the onclick function? I am using es6 template to generate html codes. I tried with ${}, but actually it will convert anything inside to string, which is not what I wanted.

I also checked something like <% %>, but somehow doesn't work as expected..

renderDate(item) {
        let self = this;
        if (!item) {
            return "";
        }
        let checked =item.selected?"checked":"";

        tmp = `<div class="day-item  align-center" id="selectDate" key="${item.name}" onclick="">
                <div class="checkbox align-center justify-center ${checked}" ${checked}>
                    <span class="iconfont icon-check"></span>
                </div>
                <span class="text">${item.name}</span>
            </div>`
        return tmp
    }
Blake
  • 7,367
  • 19
  • 54
  • 80
  • 2
    Use the DOM instead of concatenating bits of HTML? – Ry- Jul 04 '16 at 03:51
  • What do you mean by bind the item anyway? What do you want to do with it in onclick? Also why use `onclick` in first place? You are using modern javascript to render this...and 1990's onlcick method – charlietfl Jul 04 '16 at 03:53
  • @charlietfl when I click, the `item` variable also get passed to the onclick function. – Blake Jul 04 '16 at 03:54
  • Use unobtrusive event binding instead of inline and you have the object available in the callback – charlietfl Jul 04 '16 at 03:55
  • Please do not perpetuate jQuery`s incorrect usage of the term "bind" to refer to listening to events. –  Jul 04 '16 at 03:58
  • I cannot understand this question. Please specify what you expect to result, and what does result from your code. –  Jul 04 '16 at 04:00
  • there's no way to make a true object link. you have to embed an id or other smoking gun to lookup the right object on-demand. there is one trick i've used though, a look up function that acts like a map. give it an object, it returns a number, give it a number, it returns the object- the number goes in the template. – dandavis Jul 04 '16 at 04:25
  • @Blake, could you provide the function you want to be executed on click? Should it be provided by the caller of `renderDate`, or should it be defined by that function itself? – trincot Jul 04 '16 at 07:30
  • 1
    As an `ìd` property must have a unique value across the document, and your template specifies a static `id` value, does this mean you will only call this method once? – trincot Jul 04 '16 at 08:45
  • @charlietfl I doubt onclick is outdated 90s JS. No offence but I would rather use onclick similar to the way angular does `(click)="execSomething()"`. This would make it far more easy to quickly asses what code is executed on certain events. I enjoy using inline event handlers in web components the same way I use them in React or Angular. It improves so much the workflow. [How to bind this to inline event handler](https://stackoverflow.com/a/12486171/1903781) – Adrian Moisa Oct 16 '17 at 15:20

1 Answers1

1

Here is one way to do it:

class myClass {
  constructor() {
    this.onclick = null;
    this.item = null;
    // Add delegated click listener
    document.addEventListener('click', function (e) {
      // Only if click happens in #selectDate, and a click handler was defined:
      if (this.onclick && e.target.closest('#selectDate')) {
        this.onclick(e, this.item);
      }
    }.bind(this)); // `this` refers to this myClass object when clickListener is called
  }

  renderDate(item, onclick) {
    if (!item) {
        return "";
    }
    this.item = item;
    this.onclick = onclick;
    let checked = item.selected ? "checked" : "";
    
    let tmp = `<div class="day-item  align-center" id="selectDate" key="${item.name}" >
              <div class="checkbox align-center justify-center ${checked}" ${checked}>
                <span class="iconfont icon-check"></span>
              </div>
              <span class="text">${item.name}</span>
           </div>`;
    return tmp;
  }
}
  
let item = {
      selected: true,
      name: 'this is my text: click me',
      data: [1, 2, 3, 4] // some other data...
    },
    myObj = new myClass;

function processItem(e, storedItem) {
    console.log(
`You clicked element with key = "${e.target.closest('#selectDate').getAttribute('key')}".
Item = ${JSON.stringify(storedItem)}`
    );
}

// get the template, provide the onclick handler, and insert the HTML
document.getElementById('container').innerHTML = myObj.renderDate(item, processItem);
<h1>My title</h1>
<div id="container"></div>

When an instance of your class is created, a listener is added to the document. It filters click events that happened on the selectDate element, or one of its child elements. When this is the case a custom onclickcallback is called, to which the item object is passed.

The call of renderDate takes the item object, but also the above mentioned callback. It was not clear to me whether you wanted that callback to be defined within the class, or to be provided by the caller, so I went for that second possibility. To change the code to use the first pattern should not be hard.

trincot
  • 317,000
  • 35
  • 244
  • 286