Help. Radio Input - no OnChange Event


#1

I have the following React code below that renders the HTML code below that.

The resultant Radio boxes look correct but my OnChange handler is not firing.
I am seeing this generated style that hides the real radio button in favor of the icon version, if I disable the display: none, and click on the real radio button the onChange event fires properly. Am I specifying the code correctly ?

I am using Framweork7 V3 Beta 14, I also have Framework-React loaded but went to just using Framework7 markup for more control.

Thank you
John Gentilin

– Problem Style
.radio input[type=checkbox], .radio input[type=radio], label.item-radio input[type=checkbox], label.item-radio input[type=radio] {
display: none;
}

— React Code

 <div className={"list " + this.props.classes.radioList}>
    <ul >
      {this.props.options.map(opt =>
        <li key={opt.value} className={this.props.classes.radioListItem}>
          <label className={"item-radio item-content " +this.props.classes.radioLabel} id={this.props.labelId}>
            <input type="radio" name={this.props.name}
              onChange={this.handleChange.bind(this, opt.value)}
              onBlur={this.props.onBlur.bind(null, this.state.value)}
              aria-labelledby={this.props.labelId}
              checked={this.state.value == opt.value}
              className={this.props.classes.radio}
              required={this.props.required
                ? 'required'
                : undefined}
            />
            {/*- Radio icon --*/}
            <i className="icon icon-radio"></i>
            <div className="item-inner">
              <div className="item-title">{opt.text}</div>
            </div>
          </label>
        </li>
      )}
    </ul>
  </div>

-----HTML Code

<div class="list ">
  <ul>
    <li class="">
      <label class="item-radio item-content" id="existing-user-label">
        <input type="radio" name="existing-user" aria-labelledby="existing-user-label">
        <i class="icon icon-radio"></i>
        <div class="item-inner">
          <div class="item-title">Yes</div>
        </div>
      </label>
    </li>
    <li class="">
      <label class="item-radio item-content" id="existing-user-label">
        <input type="radio" name="existing-user" aria-labelledby="existing-user-label">
        <i class="icon icon-radio"></i>
        <div class="item-inner">
          <div class="item-title">No</div>
        </div>
      </label>
    </li>
  </ul>
</div>

#2

Weird, this is what works for me, just tested in React Kitchen Sink:

export default class extends React.Component {
  constructor() {
    this.state = {
      value: 'item1',
    }
  }
  onChange(e) {
    console.log('change')
  }
  render() {
    return (
      <Page>
        <Navbar title="Radio" backLink="Back"></Navbar>
        
        <List mediaList>
          <ListItem
            radio
            checked={this.state.value === 'item1'}
            onChange={this.onChange.bind(this)}
            name="demo-media-radio"
            title="Facebook"
            after="17:14"
            subtitle="New messages from John Doe"
            text="Lorem ipsum dolor sit ..."
          ></ListItem>
          <ListItem
            radio
            name="demo-media-radio"
            checked={this.state.value === 'item2'}
            onChange={this.onChange.bind(this)}
            title="John Doe (via Twitter)"
            after="17:11"
            subtitle="John Doe (@_johndoe) mentioned you on Twitter!"
            text="Lorem ipsum dolor sit ..."
          ></ListItem>
          <ListItem
            radio
            name="demo-media-radio"
            checked={this.state.value === 'item3'}
            onChange={this.onChange.bind(this)}
            title="Facebook"
            after="16:48"
            subtitle="New messages from John Doe"
            text="Lorem ipsum dolor ..."
          ></ListItem>
        </List>
      </Page>
    )
  }
}

Also this works too:

import React from 'react';
import { Navbar, Page, BlockTitle, Block, List, ListItem, Radio } from 'framework7-react';

export default class extends React.Component {
  constructor() {
    this.state = {
      value: 'item1',
    }
  }
  render() {
    return (
      <Page>
        <Navbar title="Radio" backLink="Back"></Navbar>

        <List mediaList>
          <ListItem
            radio
            checked={this.state.value === 'item1'}
            onChange={() => this.setState({ value: 'item1' })}
            name="demo-media-radio"
            title="Facebook"
            after="17:14"
            subtitle="New messages from John Doe"
            text="Lorem ipsum dolor sit amet ..."
          ></ListItem>
          <ListItem
            radio
            name="demo-media-radio"
            checked={this.state.value === 'item2'}
            onChange={() => this.setState({ value: 'item2' })}
            title="John Doe (via Twitter)"
            after="17:11"
            subtitle="John Doe (@_johndoe) mentioned you on Twitter!"
            text="Lorem ipsum dolor sit amet ..."
          ></ListItem>
          <ListItem
            radio
            name="demo-media-radio"
            checked={this.state.value === 'item3'}
            onChange={() => this.setState({ value: 'item3' })}
            title="Facebook"
            after="16:48"
            subtitle="New messages from John Doe"
            text="Lorem ipsum dolor sit amet ..."
          ></ListItem>
        </List>
      </Page>
    )
  }
}

#3

With simple markup also works:

import React from 'react';
import { Navbar, Page, BlockTitle, Block, List, ListItem, Radio } from 'framework7-react';

export default class extends React.Component {
  constructor() {
    this.state = {
      value: 'item1',
    }
  }
  render() {
    return (
      <Page>
        <Navbar title="Radio" backLink="Back"></Navbar>
        <div className="list">
          <ul>
            <li>
              <label className="item-content item-radio">
                <input
                  type="radio"
                  checked={this.state.value === 'item1'}
                  onChange={() => this.setState({ value: 'item1' })}
                  name="demo-media-radio"
                />
                <i className="icon icon-radio"></i>
                <div className="item-inner">
                  <div className="item-title">Item 1</div>
                </div>
              </label>
            </li>
            <li>
              <label className="item-content item-radio">
                <input
                  type="radio"
                  checked={this.state.value === 'item2'}
                  onChange={() => this.setState({ value: 'item2' })}
                  name="demo-media-radio"
                />
                <i className="icon icon-radio"></i>
                <div className="item-inner">
                  <div className="item-title">Item 2</div>
                </div>
              </label>
            </li>
            <li>
              <label className="item-content item-radio">
                <input
                  type="radio"
                  checked={this.state.value === 'item3'}
                  onChange={() => this.setState({ value: 'item3' })}
                  name="demo-media-radio"
                />
                <i className="icon icon-radio"></i>
                <div className="item-inner">
                  <div className="item-title">Item 3</div>
                </div>
              </label>
            </li>
          </ul>
        </div>
      </Page>
    )
  }
}

#4

Hidde checkbox shouldn’t be the case, it bypasses events correctly


#5

I guess issue can be in your onChange/onBlur handlers. Why do you need onBlur at all?


#6

Thank you for all the info.

One note, the value actually changes, the onChange handler just doesn’t fire.
So I can select either radio icon, see the value change in the form data and on the screen, but no onChange event.

If I disable the hidden attribute (with dev tools), I then see the standard radio button graphic along with the radio icon. If I click the standard radio button then the event fires and all else works like it should. I can still click the radio icon, with the same behavior, value changes but no event fires.

re:OnBlur: I am in the process of creating fw7 compatible widgets for http://winterfell.andrewhathaway.net and I want to leave most of the code intact and just change the HTML structure / styling. So to be honest, I haven’t looked into why OnBlur is needed.


#7

I think I found the problem, I was including framework-react as a require on some pages and as an import on others. i.e.
var FW7React = require(‘framework7-react’);
vs
import { Page, List, Button } from ‘framework7-react’;

Originally I had this odd error when I used import for my form element code, I would get a run time error on the “Module.exports” statement. After a lot of digging, I changed the import to a require and it worked. That one change propagated to other parts of my code and the onChange event started having an error. Tonight I went back to the fw7-react-demo code and just added in my form code. It worked so I compared code an that was the only difference.

Since I dropped the fw7-react elements in my Form element, I not longer need to import or require it, so it all works out.

I forked the demo repo, added my code to it. With this code, the runtime error is most demonstratable, go to the fw7RadioInputsOption in the formElements folder. and swap the comment on the first two lines. I could also add code to reproduce the error if it would be helpful.

My code is here https://github.com/gentijo/framework7-react-app-template, modified branch v3.

Thank you for all your help.
-John Gentilin


#8

Well, you shouldn’t mix require/module.export with es-next import/export. Framework7 esm module is designed to be used with es-next modules only. Doing require can probably (depending on bundler) include browser build, which is for testing and prototyping purpose only