npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

osci-react-form

v1.0.11

Published

* write JSX in the react containment style * automatic dependency injection on values and event handlers * instictive validation interfaces

Downloads

5

Readme

key features

  • write JSX in the react containment style
  • automatic dependency injection on values and event handlers
  • instictive validation interfaces

npm

npm install --save-dev osci-react-form

a basic example

import React, { Component } from "react";
import Form, { enhance, Input } from "osci-react-form";

export default class SampleForm extends Component {
  constructor(props) {
    super(props);

    this.state = {
      values: {},
      config: {
        asyncValidateOnBlur: true,
        asyncValidateOnInit: true,
        touchNonEmptyOnInit: true,
        fieldsToNormalize: [],
        normailzeTest: /^$/
      }
    };
  }

  render() {
    return (
      <Form scope={this} onSubmit={this.handleSubmit}>
        <Input name="username" />
        <Input name="password" type="password" />
        <button type="submit">Sign in</button>
        <button type="reset">reset</button>
      </Form>
    );
  }
}

scope attribute

  • The attribute scope is the client that has the state of Form.

  • If it is not defined, it will be the instance of Form itself.

state control methods

  • You can execute enhance(scope) to enable the state control methods.

  • This method should be executed before any execution of the methods.

  • scope can be either an instance or a class. (not plain functions. React plain functions cannot have this.)

  • It is trivial that the scope attribute and the scope argument should be the same.

fields definition

  • Form regards components with names as fields.

method caveats

If a method modifies this.state or reads it not in the 'render' method frame, put the previous state as its argument,

this.setState(prev => {
  this.setValue("username", "pororo", prev);
  return true;
});

else just use the mothod directly.

this.isValid("username");

If you implemented React.Component abstract methods like getSnapShotBeforeUpdate, you have to set the state in the immutable way. (frankly speaking...i have not tested this case yet)

this.setState(prev => {
  this.setValue("username", "pororo", prev);
  return { values: this.getCopy(prev.values) };
});

define validators

  • the custom validator interface
validator : String || { name : String, regex : RegExp || api : function, async : boolean [Optional], message : String [Optional] }
  • client definition
<input validators={[ validator1, validator2, ...]} ... />
  • built-in definition
<input name="confirm" match="password" ... />
  • the list of the built-in validators

    • type="email"
    • required
    • match="anyNameOfField"
    • notMatch="anyNameOfField"
    • pattern={/.*/}
    • assertTrue={anyCustomValidator}
    • assertFalse={anyCustomValidator}
  • ordering built-in validators with strings

<Input validators={[ 'required', validator1, 'email', 'pattern', validator2, 'match', 'assertFalse', ...]} pattern={/(1|2)/} match="password" ...built-in-validators />
  • validation scoping

You can avoid each component having the same validator objects and their value caches for the same validation functionality.

<ul>
  {arr.map((v, i) =>
    <Input key={i.toString()}
           validators={...validators}
           validationScope="serialNumber" />
  )}
</ul>
<Input validators={...validators} validationScope="serialNumber" />
  • validator caveats

    • Once validators are registered, you cannot change them.
    • api mothods should return a promise that returns a boolean.
    • The required built-in validator always goes first.

methods that reads this.state

  • 'getValue(name : String, prev : Object [Optional]) : String'

  • 'isTouched(name : String, prev : Object [Optional]) : Boolean'

  • 'syncValidate(name : String, prev : Object [Optional], value : Object [Optional]) : String || null'

  • 'syncValidateFull(name : String, prev : Object [Optional], value : Object [Optional]) : Array'

  • 'isSyncValid(name : String, prev : Object [Optional]) : Boolean'

  • 'getSyncValidator(name : String, prev : Object [Optional]) : Array'

    • no Validator class yet
  • 'getAsyncStatus(name : String, prev : Object [Optional]) : Object { [asyncName1] : 'processing' || 'resolved' || 'rejected', [asyncName2] : ... } || null'

  • 'getFieldNames(prev : Object [Optional]) : Array'

  • 'isAsyncValidating(name : String [Optional], prev : Object [Optional]) : Boolean'

  • 'isAsyncRejected(name : String [Optional], prev : Object [Optional]) : Boolean'

  • 'getAsyncErrors(name : String, prev : Object [Optional]) : Object { [asyncName1] : 'message or name', [asyncName2] : ... } || null'

  • 'getAsyncIdleFields(name : String, prev : Object [Optional]) : Array'

  • 'getProcessingPromises(prev : Object [Optional]) : Array'

methods that modifies this.state

  • 'setValue(name : String, value : any, prev : Object) : Boolean'

  • 'deleteValue(name : String, prev : Object) : true'

  • 'touch(name : String, prev : Object) : Boolean'

  • 'touchAll(name : String, prev : Object) : Boolean'

  • 'untouch(name : String, prev : Object) : true'

  • 'asyncValidate(name : String, prev : Object, value : Object [Optional]) : Promise<{asyncName : String, message : String, value : Object, result : Boolean}>'

  • 'normalize(prev : Object, names : Array [Optional]) : undefined'

    • cleans up empty strings for the names in the second argument or field names defined in the configuration of 'fieldsToNormalize'

    • this method is for dynamic fields that are not assigned any values to.

plain methods

  • 'getCopy(original : Object) : Object'

    • deeply copy all properties

submit interface

<Form
  onSubmit={this.onSubmit}
  onSuccess={this.onSuccess}
  onFailure={this.onFailure}
/>
  • Form attributes could have onSubmit, onSuccess and onFailure.
  • onSubmit is supposed to return a promise. If you cannot do so in certain cases like bcrypt, you have to implement this.setState({submitting : false}) manually.
  • The inner source code of submit handling is below
submit() {
  const { scope } = this;
  const body = scope.getCopy(scope.state.values);
  const submitAction = this.props.onSubmit(body);
  if (submitAction instanceof Promise) {
    submitAction
      .then(
        (!scope.isUnmounted && this.props.onSuccess) || (result => result),
        (!scope.isUnmounted && this.props.onFailure) || (result => result),
      )
      .then(this.handleAfterSubmitCompletion);
  }
}

control the unmounted component

  • You can put the code below to avoid the unmounted component error with setState.
if (scope.isUnmounted) {
  // scope.setState({ any });
}

the sample page

http://osci-react-form.surge.sh/

test the sample code

git clone [email protected]:OpenSourceConsulting/osci-react-form.git
cd osci-react-form
npm install
npm start

update logs

  • 2018/5/15 update logs have been refreshed.

issues

  • eager

    • test React.Component abstract methods with the state control methods
    • asyncValidateOnChange, asyncValidateOnChangeForNonText, asyncValidateOnBlurForNonText, suppressAutoDenpency
  • lazy

    • uncontrolled component 디자인 구상, ref? no? ex) type="file"
    • html5 의 모든 스펙을 구현해야한다. (range, textarea, contenteditable, submit action async ...)
    • old browser, study of xss cases
    • old browser, onSubmit setState promise event loop hole 학습 및 테스트, 최신브라우져는 테스트 완료
    • customizing 혹은 logging 을 위해 다양한 hook 을 제공해야한다. promise 의 대부분 stack 에서 logging 할 수 있도록 할 것이다.
  • extra

    • componentDidCatch 사용성 테스트, 좋은 인터페이스인가
    • dev logging, dev minifying 구현
    • chrome dev tool perfomance test

LICENSE

  • The MIT License (MIT)

  • Copyright (c) 2018 OSCI