Inferno: Inferno 3.5.0 and controlled checkboxes and radio

Created on 14 Jun 2017  路  54Comments  路  Source: infernojs/inferno

Controlled inputs like type='checkbox' or type='radio' generate the onClick events but do not fire onChange events. This is my fault also, I checked the onClick only in https://github.com/AlgoTrader/inferno-controls.

bug to verify

All 54 comments

@AlgoTrader Can you send PR for this functionality it might be something related to these lines:
https://github.com/infernojs/inferno/blob/master/packages/inferno/src/DOM/wrappers/InputWrapper.ts#L94-L96

You can also test if onchange works instead of onChange, just to narrow down the case here.

for checkboxes, both onChange and onchange work. For radio neither work

My research is following

1) dom handlers are installed correctly
2) onchange for radio does not generated due to manipulations with value, if I comment out applyValue(nextPropsOrEmpty, dom) onChange start work for initially enabled radios

It seems applyValue is somewhat incorrect. Radio inputs are unique that value usually never changes, only checked changes. They have both checked and value props and the latter is constant

@AlgoTrader can you contribute fix to Inferno? PR would be nice. I can look into these issues, but the thing is that I have my hands full of other work.

I will try my best

I face serious troubles with Inferno way of working with controlled components. Inferno rely on the assumption that input's onClick and onChange may cause input's props change. Right after calling callback we check if the props changed and try to apply them. We should not do it. If parent component will change its state, then it will schedule input's render and we will get new props in 'normal way' in componentWillReceiveNewProps and render. onClick and onChange calls should never expect new props right after the callback call.

Lots of current testcases expect Input to apply a new value immediatly after the click handler finish. This is very incorrect assumption. Input's callbacks like onChange or onClick may schedule input re-render (usually by changing parent state that go to child props).

I believe those test cases were cross verified with React, could you check React JSFiddle to verify that?

I commented out applyValue(nextPropsOrEmpty, dom); as @AlgoTrader discusses above.

I tried commenting-out this call to stopPropagation. I tried commenting-out or disabling all onchange functions. I'm only able to change the checkbox after I run the following from the console :(

[].map.call(document.getElementsByTagName('input'), checkbox => 
  checkbox.id = String(checkbox.id) + ':)');

Any ideas?

Fixed in dev branch and can be closed.

when will this be published?

The same question.
When? @Havunen

@Havunen would you take a look at merging and publishing this for us?

I will make v4 beta next weekend. This will be available then for testing.

Internal vNodes / removing normalization process won't be part of v4 as its taking so long to get it working correctly.

Inferno v4 software is one I've been anxiously looking forward to. @Havunen good you're still alive and kickin' :)

:(

@iambumblehead Inferno v4 is available by using following command npm i --SE inferno@next use "next" tag for all packages. Also NOTE: inferno-component is now inside inferno main package and inferno-component is deprecated and can be removed.

If you find any issues please open Github ticket.

:|

I tried using inferno@next and am getting this error

ReferenceError: process is not defined

I resolved it by aliasing 'inferno' to 'inferno/dist/inferno' at my build tool. A solution (if you think this this is a problem) may be to define a 'browser' property in the package.json, which defines a specific entry file for browser applications.

{
  "browser": "dist/inferno.js"
}

@anthony-redFox checkboxes are almost working in @next and its awesome thank you!

checking/unchecking the checkbox does result in an error for me,

function applyValue(nextPropsOrEmpty, dom) {
    /* ... */
    if (type && type !== dom.type) {
      dom.setAttribute('type', type);
    }

An error with a stack message showing two calls,

TypeError: dom is undefined
  applyValue
  onCheckboxChange

At least the checkbox does check and uncheck now, so the update is an overall upgrade

sorry to bomb this thread with messages but another issue when trying to use the newest sources with an application that uses jasmine unit testing.

node_modules/inferno/dist/index.js:1638
var G = (window || global);
        ^
ReferenceError: window is not defined

This would be resolved by checking for window using typeof window === "object"

var G = typeof window === 'object' ? window : typeof global === 'object' ? global : {};

this same issue breaks a server side rendering application I'm using w/ inferno...

node_modules/inferno/dist/index.js:1638
var G = (window || global);
        ^

ReferenceError: window is not defined

I tried wading through some of these issues. The main file specified in the inferno package.json breaks in node even if you correct the 'window' issue. Its necessary to specify a different main file and fix the 'window' issue inside that,

  "main": "dist/inferno.js",

After that, inferno-server fails (I'm also using inferno-hyperscript)...

Error: Inferno Error: renderToString() received an object that's not a valid VNode, you should stringify it first. Object: "[{"children":[null,null,{"children":null, ...
    at throwError (node_modules/inferno-server/dist/inferno-server.js:48:15)

@iambumblehead Thanks a lot for doing some testing. I have fixed many of the issues you reported above, I will do another beta release so you can check if it fixes all your issues :)

Are you also using inferno-compat ?

@iambumblehead I just published new packages for next inferno packages are 4.0.0-6 and babel plugin is 4.0.0-21 please check if that fixes the issues you seen :)

@Havunen ok I need a moment to clean a few things up here... and I'll let you know how it goes

I updated the version in my package.json

    "inferno": "4.0.0-6",
    "inferno-hyperscript": "4.0.0-6",
    "inferno-server": "4.0.0-6",

And installed

$ cat node_modules/inferno/package.json | grep version\":
  "version": "4.0.0-6"

And trying to render a page shows a new error

node_modules/inferno-server/dist/index.js:42
    throw new Error(("Inferno Error: " + message));
    ^

Error: Inferno Error: a runtime error occured! Use Inferno in development environment to find the error.
    at throwError (node_modules/gani/node_modules/inferno-server/dist/index.js:42:11)
    at renderVNodeToString (node_modules/gani/node_modules/inferno-server/dist/index.js:315:9)
    at Object.renderToString (node_modules/gani/node_modules/inferno-server/dist/index.js:319:12)

Can you use development build please, so we get better error message

I'll try. I'm not too familiar with setting things up that way.

process.env.NODE_ENV needs to be something else than "production" or maybe you are requiring minified inferno package, is it alias issue?

node_modules/inferno-server/dist/index.js:42
    throw new Error(("Inferno Error: " + message));
    ^

Error: Inferno Error: renderToString() received an object that's not a valid VNode, you should stringify it first. Object: "{"sel":"div.:.uiroot","data":{},"children":[]}".
    at throwError (node_modules/gani/node_modules/inferno-server/dist/index.js:42:11)
    at renderVNodeToString (node_modules/gani/node_modules/inferno-server/dist/index.js:309:17)
    at Object.renderToString (node_modules/gani/node_modules/inferno-server/dist/index.js:319:12)

There seems to be invalid object {"sel":"div.:.uiroot","data":{},"children":[]} correct object shape is somethig like this:

export interface VNode {
  children: any;
  childFlags: number;
  dom: Element | null;
  className: string | null;
  flags: number;
  key: any;
  parentVNode: VNode | null;
  props: Props | null;
  ref: Ref | Refs | null;
  type: any;   <== This should be "div"
}

Can you check where that object is coming from?

My apology --that was a vnode from a different library I was trying out. I'll make changes to use inferno-hyperscript and let you know the result.

Ok --one small issue of note, CJS style users need to make this change, though perhaps only I need to make this change do to an unusual build tool I'm using.

//const h = require('inferno-hyperscript');
const {h} = require('inferno-hyperscript');

Anyway, this is the error I'm seeing now after restoring inferno-hyperscript...

ReferenceError: process is not defined [Learn More] inferno_400_6_dist_index.js:180:1
ReferenceError: inferno_400_6_dist_index is not defined [Learn More] inferno_400_6_index.js:2:1

I added this to my build tool...

  aliasarr : [ [
    'inferno',
    'inferno/dist/inferno'
  ] ],

and it seems to be fully operational again in the browser environment

Yeah default exports will be removed in v4. Industry is moving that direction and we follow it too. so all imports/requires need to be named.

Checkbox does not uncheck for me. Clicking a radio control has no effect either, other form controls appear still work fine.

How are you rendering it ? Can you create steps to reproduce somewhere?

One moment... I'll try to make a small example and copy/paste it here.

let inferno = require('inferno'), // reproduced w/ @4.0.0-6
    infernoh = require('inferno-hyperscript').h;

inferno.render(
  infernoh('input.testbox', {
    type : 'checkbox',
    name : 'testbox',
    checked : true
  }), document.body.firstElementChild);

I'm confused, If you render checked: true, it will always be true: see https://jsfiddle.net/hLtfvoj3/

How would it be unchecked if the initial value is true/"checked"?

This is controlled example: https://jsfiddle.net/z4u103qz/

Or if you only want to set initial value you can use defaultChecked like this: https://jsfiddle.net/ht76avv0/

awesome that works well. I'm not using the react state/props system here... thank you very much finding/showing this to me. The only outstanding issue I have is the radio control and perhaps a recommendation to add a specific browser entry script to the package.json

"browser": "inferno/dist/inferno"

Using defaultChecked with the radio form control makes the radio options selectable, but selecting one radio option does not deselect the other options.

This is the behaviour I would expect to see with a radio control,
https://www.w3schools.com/html/tryit.asp?filename=tryhtml_radio

Only one option should selectable at any time.

--- edit
this looks like another issue originating from me... the radio controls returned here have different name attributes. I'll change that.

Do you have the radio buttons in same "name" group?

I changed the name values to use the group name and all is well! everything works :)! thank you!

Good to hear! :) Happy to help!

Since I am not using state management aspects of inferno and am just diffing/publishing vnodes, I am curious to know...

How much of the inferno sources would you approximate are dedicated to managing state vs diffing of vnodes?

I'm not entirely sure... difficult question, because there are non-direct relations in code which could be removed if there would be no Components at all? Don't you use any components? I guess 3kb gzip could be removed? or something like that

I'm developing a concept that manages state in an entirely different way. I'd like to share a small comparison of my brief experience with react and snabbdom compared to inferno with this app specifically.

The inferno interface is smaller than snabbdom's. snabbdom requires node attributes and properties to be added inside an additional namespace of 'props' or 'attrs'.

For example, instead of { href : '#' } something like { props : { href: '#' } } is needed. This seems small but it requires a few additional lines per component and an understanding of props vs attrs.

There are many differences between the names of properties used in the snabbdom interface as compared to inferno's interface, for example, where Inferno uses 'for', snabbdom uses 'htmlFor'. Snabbdom requires one to keep track of the previous vtree for applying subsequent patches and Inferno does not require that. Snabbdom elements are malformed if the selector string defines an id part at the end of the selector rather than the beginning and Inferno does not have that issue.

I did not measure speed, but snabbdom 'felt' as fast as Inferno. A possible strong point for snabbdom is that it uses plugins for its behaviour so that one can add support for features granularly. Snabbdom always completely re-renders a vnode when its selector string is changed, but there is a className namespace that can be used to specifically change _just_ the classNames. The plugins and className details aren't found in inferno, but one might say that Inferno provides a simpler interface managing these details automatically.

As far as react goes, Using it in an enterprise environment has been great, however replacing inferno with it in this specific application was too difficult because react requires enterprise tooling and isn't as nimble for some purposes as inferno and snabbdom are.

tldr; the Snabbdom and Inferno sources are simple to use outside of traditional enterprise tooling. Inferno's interface is simpler than Snabbdom's in a few different areas. I prefer inferno but would be happy using snabbdom as well.

Was this page helpful?
0 / 5 - 0 ratings