volijs / nestedlink Goto Github PK
View Code? Open in Web Editor NEWCallback-free React forms with painless validation.
License: MIT License
Callback-free React forms with painless validation.
License: MIT License
Wouldn't be better to render NumberInput as type "number" instead of "text"?
<input { ...props } type="number"
Some browsers then interpret it better and allows to increment numbers by mouse or keys.
The pattern is to override component.linkAll()
.
linkAll
of the base class to produce the relevant links.validationError
and add it to the cache object.It's damn cool pattern which deserves to be reflected in tutorials.
When you update the link to object or array, you still have to return the value.
link.update( obj => { delete obj[ key ]; return obj; } )
Which is not good. Stupid code is always not good. It should look (and still work) like this:
link.update( obj => delete obj[ key ] )
Then it will be perfect. In the next minor version.
I'm creating a training course/docs for nestedlink as part of my https://www.omscs.gatech.edu/cs-6460-educational-technology class. I'm pretty far away from completing the material but was wondering if you would be willing to go over the final materials for accuracy once I finish them (way in the future). This is my personal account, rhan-mentad was my work account.
What I'm doing wrong ?
import Link, { LinkedComponent } from 'valuelink';
import { Input } from 'valuelink/tags';
export default class extends LinkedComponent {
state = {};
render() {
<Input {...rest} />
}
}
And I'm trying to use in another component ..
import Link, { LinkedComponent } from 'valuelink';
import MyInput from 'components/MyInput';
export default class extends LinkedComponent {
render() {
const linked = this.linkAll();
return <MyInput valueLink={linked.fieldTest} />
}
}
Somehow it should be possible to only check validation, if field is touched or onBlur (switch to the next field)?
Hi,
I tried using the positive prop with NumberInput. However, React throws the following warning-
"Warning: Unknown prop positive
on tag. Remove this prop from the element. For details, see https://fb.me/react-unknown-prop
I believe this is due to the fact that the props are directly passed to the underlying input element in the render method of NumberInput.
So I have been debugging this for my coworker and I think I discovered a bug with Input.
The situation is that we have two checkboxes. If the first checkbox is ticked, it should set the second checkbox to unticked.
Functional code:
// componentLink = Link.state((parent_obj), 'component_data')
// componentLink.value = {
// 'first_checkbox_key': { 'enabled': [true/false] }
// 'second_checkbox_key': { 'enabled': [true/false] }
// }
const Container = (props) => {
const { links } = props; // Directly passing componentLink in props also works
const { componentLink } = links;
return
<div>
<FirstCheckbox links={links}/>
<SecondCheckbox links={links} />
</div>
};
const FirstCheckbox = (props) => {
const { links } = props;
const { componentLink } = links;
const secondEnabledLink = componentLink.at('second_checkbox_key').at('enabled');
const firstEnabledLink = componentLink.at('first_checkbox_key').at('enabled');
const change = firstEnabledLink.action((old, event) => {
const checked = event.target.checked;
firstEnabledLink.set(checked);
if (checked) {
secondEnabledLink.set(false);
}
});
return <div>
<input type='checkbox' value={firstEnabledLink.value} onChange={change}/>
</div>
};
const SecondCheckbox = (props) => {
const { links } = props;
const { componentLink } = links;
const secondLinkEnabled = componentLink.at('second_checkbox_key').at('enabled');
return <div>
<Input type='checkbox' checkedLink={secondLinkEnabled}/>
</div>
};
tags.jsx/Input and CheckedLink doesn't work
Replacing the first checkbox with a checkedLink using Input from tags.jsx
and an onChange doesn't work.
const firstEnabledLink = componentLink.at('first_checkbox_key').at('enabled')
.onChange((enabled) => {
console.log("I was hit", enabled);
if (enabled) {
console.log("I am disabling thingy");
secondLink.set(false);
console.log(secondLink.value); // Remains 'true'
}
});
...
<Input type='checkbox' checkedLink={firstEnabledLink}/>
Adding an onChange function the normal way also doesn't work
const handle_click = (firstLink) => {
return function (e) {
const val = e.target.value;
if (val === 'false') {
firstLink.value = false; //Also tried .set(false), .update((x)=> false), .action
console.log(firstLink.value);
}
}
};
...
<Input type='checkbox' checkedLink={firstEnabledLink} onChange={handle_click(firstEnabledLink)}/>
I'm getting the "Module not found" build error after installing valueLink
and linked-controls
in my NextJS project. I have checked the module directory, and ./node_modules/valuelink
doesn't have a node_modules
subdirectory, so I wonder how it is supposed to work. Are we supposed to have tslib
available globally? I believe it's added when you create a CRA project, but it's definitely not present in my NextJs project.
If we need to add it manually, do you want to update your instructions?
Here's the full output:
> [email protected] dev C:\Projects\Galaxias\file-storage-ui
> next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
info - Using webpack 4. Reason: future.webpack5 option not enabled https://nextjs.org/docs/messages/webpack5
event - compiled successfully
event - build page: /
wait - compiling...
error - ./node_modules/valuelink/lib/link.js:1:0
Module not found: Can't resolve 'tslib'
null
Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json
Error from chokidar (C:\): Error: EBUSY: resource busy or locked, lstat 'C:\DumpStack.log.tmp'
Error from chokidar (C:\): Error: EBUSY: resource busy or locked, lstat 'C:\hiberfil.sys'
Error from chokidar (C:\): Error: EBUSY: resource busy or locked, lstat 'C:\pagefile.sys'
Error from chokidar (C:\): Error: EBUSY: resource busy or locked, lstat 'C:\swapfile.sys'
event - compiled successfully
I want to set calculated result to state when update values.
can I do?
Hi,
when I do shallow rendering in tests for components which use valuelink the snapshots are of enoumos size.
Can you propose any solution to this? Do I need to mock valueLink?
Please see the attached example snapshot
AccountSettings.txt
IE 9 does not fire an input event when the user deletes characters from an input (e.g. by pressing Backspace or Delete, or using the "Cut" operation)
https://developer.mozilla.org/en-US/docs/Web/Events/input#Browser_compatibility
So the onChange event isn't triggered by deleting characters -> another event should be used in case of IE9.
Steps to reproduce:
Input
of type="email"
(The code is basically the same as in issue #23, with the FormInput
seperated into another component. You can see the code in the Github project.)Behaviour
All leading and trailing whitespaces are removed, and the cursor is set in front of the input value.
This behaviour seems to appear for all inputs except for spaces, if there are leading or trailing whitespaces after the user input was applied.
Expected Behaviour
It might still be a problem related to the setup.
Btw: I'll try to implement the other things you suggested the next days. (There are e. g. functions implemented for the validation, even though they are currently not in use.)
And thank you for your help so far. ;)
Following code do this. You can add car to the list of cars. You can change manufacturer name. When I have defined items in state as ES6 classes then I cannot change the manufacturer name. With literal objects everything works fine. Is this bug or I do something wrong?
import React from 'react';
import ReactDOM from 'react-dom';
import Link from 'valuelink';
import { Input } from 'valuelink/tags';
class CarModel {
constructor() {
this.manufacturer = 'default';
}
}
class Car extends React.Component {
render() {
let carLink = this.props.carLink;
let val = carLink.value.manufacturer;
return (
<li><Input type="text" valueLink={ carLink.at('manufacturer') } /> { val }</li>
)
}
}
class CarList extends React.Component {
constructor(props) {
super(props);
this.state = {
cars: []
};
}
handleAdd() {
let cars = this.state.cars;
cars.push(new CarModel());
this.setState({ cars })
}
render() {
let cars = Link.state(this, 'cars').map((car, i) => (
<Car key={ i } carLink={ car } />
));
return (
<div>
<ul>{ cars }</ul>
<button onClick={ this.handleAdd.bind(this) }>Add Car</button>
</div>
)
}
}
ReactDOM.render(
<CarList />,
document.getElementById('root')
);
I have got the state like the following:
state = {
places: {
name: string,
nearByPOI: {
name: string,
location: {
latitude: number,
longitude: number
}
}[]
}[]
}
I wonder how to link, for example to state->places->nearByPOI->name
properties?
Hi there!
I have a validation for a link that uses a different state property (not the one associated to the link I'm validating). When that external state property changes, the validation doesn't rerun. This leaves the link error property in a not trustworthy state. The external state property may leave the link with an error but I won't know until the state associated with the link changes.
A workaround for this would be having a mechanism to run validation on a link manually, but I couldn't find a way to do so. Any other suggestions?
Thanks in advance!
Hello,
I'm using NumberInput because it strips out letters and is convenient. However I noticed that if I delete the number it does not in fact update the link associated with it. I use validate.js against the json object everything links to when the user submits to validate input. Thus it can result in differences between what is shown on the screen and the data. It would be good to have a prop on NumberInput to allow empty input to change the link (can set it to undefined or null).
Thanks!
When using valuelink on a dropdown with something like
this.linkRole = VLink.state(this, "role").onChange(this.onChangeRole);
<Dropdown selectedKey={valueLink.value}
onChange={(event, option, index) => valueLink.set(option.key)}
the onChange function is called before this.state.role is set, giving a value which is different from the one still in the state.
In some situations this is a problem because we know the value has changed but the state still has the old value - how can we wait for the state change to happen so that the state reflects the current drop down selection?
exporting a jsx file would require a compilation step for node_modules
in other apps, other projects/react packages never export jsx
file directly, they export the compiled version of jsx
-> js
, just like the export of valuelink.js
Thanks for the great library!
I typically link all state by using inheritance from LinkedComponent. It is a way based on class inheritance. It works. However, I have found that React Hooks from (16.8) simplify code a lot but they require components to be functions, not classes. I would like to use something similar to this.linkAll()
but within functions where I could combine the links with React.useState()
. I am trying to achieve something similar to the following. How should I do it properly?
const MyComponent = (props: { data: { field1: string }}) => {
const [state, setState] = React.useState(props.data);
const links = AnalogyOfLinkAll(state, setState); // <----- How can I do this?
return <input value={links.field1.value} onChange={(v) => links.field1.set(v)} />;
};
For example:
class Edit extends LinkedComponent {
state = {}
render() {
return (<div><Input valueLink={ this.linkAt('name')}</div>)
}
I would like to set the state when the name value is changed by the user
Edited with a different question since I resolved my own previous question.
Is there a difference between using .at and .set vs .value assignment, or are the two behaviors the same?
const rulesLink = Link.state(this, 'rules'); //An array of objects
const activeLink = Link.state(this, 'rules_active')
.onChange((enabled) => {
rulesLink.map((ruleLink) => {
ruleLink.at("active").set(enabled);
return ruleLink.value; })
});
//activeLink is assigned to a checkbox input
versus
const rulesLink = Link.state(this, 'rules');
const activeLink = Link.state(this, 'rules_active')
.onChange((enabled) => {
rulesLink.map((ruleLink) => {
ruleLink.value.active = enabled;
return ruleLink.value; })
});
//rulesLink is mapped over and sub components are created for each ruleLink in rulesLink
I know the following code doesn't actually update the child subcomponents which have checkboxes mapped to 'active' on each child rule which is why I am wondering
const rulesLink = Link.state(this, 'rules');
const activeLink = Link.state(this, 'rules_active')
.onChange((enabled) => {
_.each(this.rules, (rule) => rule.active = enabled);
})
Some React components have onHide/onChange/other functions which store the functions to the DOM (beyond our control, library components). Thus if we pass it something like:
class SomeComponent extends React.Component {
render() {
const { someLink } = this.props;
return <Modal onHide={someLink.action((value, event) => !value)} />
}
}
the function bound to the onHide can get out of sync with the state (it saved a reference to the old Link object to the DOM on first creation instead of re-rendering it).
The workaround for this is to do something like
class SomeComponent extends React.Component {
boundFunction() {
const { someLink } = this.props;
someLink.set(false); // Some Value
}
render() {
return <Modal onHide={this.boundFunction} />
}
}
It would be nice to have a convenience function on LinkedComponent which can "generate this boundFunction for you". Maybe the usage interface would be something like:
class SomeComponent extends LinkedComponent {
//Implicitly from LinkedComponent
bindLink(somePropString, callback) {
const propLink = this.props[somePropString];
//Or some other way to make it more generalized?
link.update(callback);
}
render() {
const { someLink } = this.props;
return <Modal onHide={this.bindLink(somePropString, () => {})} />
}
}
function isRequired( x ){ return x && String( x ).length }
isRequired.message = "Field is required";
Add documentation about radio types..
How can I do this..
<Input type="radio" name="radio" checked checkedLink={linked.at('image')} /> Banner
<Input type="radio" name="radio" checkedLink={linked.at('image')} /> Logo
I want a property image be a string with..
image: 'banner' or 'logo'
Trying to require
valuelink server-side results in an error complaining that window
is not defined:
$ node
> require('valuelink')
ReferenceError: window is not defined
at /Users/jwalton/benbria/loop/node_modules/valuelink/dist/index.js:1:982
at n (/Users/jwalton/benbria/loop/node_modules/valuelink/dist/index.js:1:131)
It looks like this is some kind of artifact of using rollup to bundle things, because window
is only referenced here, which would never get executed server side in the first place.
Found your library via Stackoverflow, it's very useful for my current project, so thanks for releasing it as Open Source Software!
I've copied your userlist-example over to my build-env and it works, mostly. There's just one issue - I loose focus after every letter entered in the input-fields.
I thought the problem might be caused by the modal-overlay - but after implementing nestedLink-methods in my own project, I have the same issue with loosing focus in the input-fields. And I don't use a modal.
After every letter I enter, the cursor is gone and I have to click in the input-field again to enter the next letter.
The issue is probably caused by the linkToObject.at
-method, which I'm using to autosubmit the input-value in conjunction with onChange
, in the first input-field in this example:
render() {
const linked = Link.all ( this, 'sequence', 'command', 'info' ),
infoLink = this.props.sortData.at( 'info')
const setValue = (x, e) => e.target.value
return (
<div { ...this.props }>
<span className="sequence-order">{linked.sequence.value}</span>
<input value={ linked.info.value } onChange={ infoLink.action( setValue ) }/>
<input valueLink={ linked.info }/>
</div>
);
}
The issue doesn't appear in the second-input-field, where I'm using a "simple" valueLink. But since I don't want to add a submit-button to commit its value to the parent, I prefer the more elaborate mechanism with onChange
.
I'm on:
Hey i'm trying to use your valueLink approach to validate my user inputs.
The issue i get is that the input elements lose focus when i type one character. So i have to click in the form a second time to write again. This happens after each character.
But there are good news. The validation itself works perfect.
I'm new to react, so it is also possible that i missed a major point.
Object.getPrototypeOf( 1 ) throws in IE11
As in the docs, I use import { Input } from 'valuelink/lib/tags'
It's transpiling fine, but in the browser code I get:
Uncaught SyntaxError: Unexpected token import
BTW in your README.md it's still import { Input } from 'valuelink/tags.jsx'
, but that file does not exist anymore in the NPM?
true
or false
, emit checked
instead of value
.I'm using NestedLink with typescript.
When I extend LinkedComponent
and I want to use links
member in render
method, links
is null.
One of the problems with links is that they break pure render optimization.
An upcoming release of React contains deprecation message for their crappy valueLinks, which actually is the great opportunity to improve links design. We don't have to keep backward compatibility any more.
Hi! Is there a way to not show errors at the first render of a component?
render() {
const nameLink = Link.state(this, 'name')
nameLink.check(v => v, 'Name is required')
return (
<form>
<Input valueLink={nameLink} />
// Here will be Error shown when component will mounted
</form>
)
}
I use import { Select } from "valuelink/tags";
and get this typescript error
Error:(5, 24) TS7016: Could not find a declaration file for module 'valuelink/tags'. '/home/---/node_modules/valuelink/tags.js' implicitly has an 'any' type.
Try `npm install @types/valuelink` if it exists or add a new declaration (.d.ts) file containing `declare module 'valuelink';`
I wrote small example:
https://codesandbox.io/s/xenodochial-colden-7pb59
When I start to type in input box, after second key is pressed, error with Synthetic event occurs.
I tried also useSafeLink, but it is not a solution.
But when I use variable to init useLink, everything works fine:
https://codesandbox.io/s/late-tree-vqlqp
Am I doing something wrong, or is it a bug?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.