SkillAgentSearch skills...

Jquery.parcel

A jQuery plugin designed to simplify and guide the OO encapsulation of client side Javascript code and more...

Install / Use

/learn @luning/Jquery.parcel
About this skill

Quality Score

0/100

Category

Design

Supported Platforms

Universal

README

jQuery.parcel is a jQuery plugin designed to simplify working with complex forms. It provides an Object-Oriented encapsulation of forms and their field groups using a straighforward declarative syntax. It enables some very powerful ways for decomposing forms into conceptual parcels, and provides meaningful abstractions for these parcels.

"Two Minute Tour":#quickTour

** "Build a Parcel":#quickTour_buildParcel ** "Simple Operations":#quickTour_simpleOp ** "Bind Events":#quickTour_event

"Learn More":#more

** "Mixin Behaviours":#more_behav ** "Build Composite Parcel":#more_compositeParcel ** "Add/Remove DOM elements Dynamically":#more_sync ** "Virtual Field":#more_virtual

"API Reference":#api

** "Parcel":#api_parcel *** "Build Parcel":#api_parcel_build *** "Parcel Operations":#api_parcel_op ** "Field":#api_field *** "Field Operations":#api_field_op *** "Field Events":#api_field_event ** "Form Inputs":#api_input ** "Extend Parcel":#api_ext ** "Utility":#api_util

"Q&A":#qa

<h1><a name="quickTour">Two Minute Tour</a></h1> <h2><a name="quickTour_buildParcel">Build a Parcel</a></h2>

Given a HTML snippet:

<pre> <div id="person"> <select name="title"> <option>Mr</option> <option checked="checked">Mrs</option> </select> <input type="text" name="firstname" value="Jane"/> <input type="text" name="lastname" value="Doe"/> </div> </pre>

You create a parcel like this:

<pre> var person = $("#person").parcel(); </pre>

This builds a parcel representing @person@ with all fields set up automatically from their name attribute of the input field.

(The fields are actually jQuery wrappers of each form field element in the specified parcel)

<pre> person.title; person.firstname; person.lastname; </pre> <h2><a name="quickTour_simpleOp">Simple Operations</a></h2>

@firstname@ is a person field and calling @state()@ will simply return the field value, just like @val()@ on a jQuery object.

<pre> person.firstname.state(); #=> "Jane" </pre>

To change @firstname@ to new value, just pass the value into the @state()@ method.

<pre> person.firstname.state("John"); </pre>

This is just like @person.firstname.val("John")@ in jQuery, but with the appropriate events are fired as if a real user typed the value into the field.

Setting the values of the entire person parcel is just as easy!

<pre> person.state({ title: "Mr", firstname: "John", lastname: "Smith"}); </pre>

Remember that all the user events get fired (ie. change, blur, click, etc).

Calling @state()@ on the person parcel simply returns the current state of the parcel as an object:

<pre> person.state(); #=> { title: "Mr", firstname: "John", lastname: "Smith"} </pre>

You can tell if the state has changed with @isDirty()@:

<pre> person.isDirty(); #=> true </pre>

Person is flagged as dirty, since the state of person has been changed since initialization.

Set the original state to the parcel with @resetState()@

<pre> person.resetState(); #=> { title: "Mrs", firstname: "Jane", lastname: "Doe"} </pre> <h2><a name="quickTour_event">Bind Events</a></h2>

Let's say you want to have a @label@ element update with changes in the value of a field. Use the @bindState()@ method passing in the CSS selector:

<pre> person.firstname.bindState("#first_name_label"); </pre>

Now any change of @firstname@ will update the value of the label you specified.

But what if you wanted a single label to reflect all of the fields? Simply pass a transformation function as the second argument to @bindState()@ like so. The state will be passed in as a parameter to this function so you can easily extract what you need.

<pre> person.bindState("#id_of_summary_span", function(s) { return s.title + " " + s.firstname + " " + s.lastname; }); </pre>

Any changes to person fields will now update the summary span using the specified transformation function.

<pre> person.firstname.stateChange(function(state) { /* custom logic */}); person.stateChange(function(state) { /* custom logic */}); </pre>

State change of the @firstname@ field or @person@ parcel will trigger the custom handlers and pass in the latest state object.

<h1><a name="more">Learn More</a></h1> <h2><a name="more_behav">Mixin Behaviours</a></h2>

You can extend a parcel by mixing in new behaviour.

<pre> function Person() { this.summary = function() { var s = this.state(); return s.title + " " + s.firstname + " " + s.lastname; } } var person = $("#person").parcel(Person); person.summary(); </pre>

Define behaviour @Person@ as a function, build parcel with the behaviour, and the @summary()@ method will be mixed into the parcel.

Behaviour mixins are the recommended way to include custom logic for a specific parcel.

You can also specify the behaviour function in the containing DOM element by supplying a @parcel@ attribute:

<pre> <div id="person" parcel="Person"> ... </div> </pre>

Then:

<pre> var person = $("#person").parcel(); person.summary(); </pre>

jQuery.parcel will mixin the @Person@ behaviour for you automatically.

<h2><a name="more_compositeParcel">Build Composite Parcel</a></h2>

You can build a composite parcel with another parcel as field by setting up @parcel@ property on any DOM element which can be used as a container (typically _div_s, _fieldset_s, etc).

With this HTML:

<pre> <div id="person"> ... <div parcel name="contact"> <input type="text" name="number" value="+61 2 9555 0123" /> <input type="text" name="type" value="work" /> </div> </div> </pre>

Then:

<pre> var person = $("#person").parcel(); person.state(); #=> { title: "Mr", firstname: "John", lastname: "Smith", contact: { number: "+61 2 9555 0123", type: "work" } } person.contact.state(); #=> { number: "+61 2 9555 0123", type: "work" } person.contact.number.state(); #=> "+61 2 9555 0123" </pre>

Build a parcel with a field containing an array of sub-fields with the same name (e.g. person may have multiple emails) by setting @parcel@ property to @[sub_field_name]@ on the container DOM element.

Given this HTML:

<pre> <div id="person"> ... <div parcel="[email]"> <input type="text" name="email" value="a@my.com" /> <input type="text" name="email" value="b@my.com" /> <div> </div> </pre>

Then:

<pre> var person = $("#person").parcel(); person.state(); #=> { title: "Mr", firstname: "John", lastname: "Smith", email: ["a@my.com", "b@my.com"] } person.email.state(); #=> ["a@my.com", "b@my.com"] person.email.items[0].state(); #=> "a@my.com" </pre> <h2><a name="more_sync">Add/Remove DOM elements Dynamically</a></h2>

Adding a new DOM element dynamically will add the corresponding field. Any event registered on a parcel works for the newly added field too. (Pretty much like jQuery live events).

Given two emails in the DOM already, then:

<pre> var person = $("#person").parcel(); var newEmail = $("<input type="text" name="email"></input>"); person.container.append(newEmail); newEmail.sync(); var emailCount = person.emails.length; </pre>

@emailCount@ is @3@, reflects the added email.

jQuery.parcel extends jQuery with the @sync()@ method. Just call it after the new elements are added.

The same thing happens when removing DOM elements, the fields will be removed.

Say we have two emails in the DOM already, and we remove the last one:

<pre> var person = $("#person").parcel(); person.container.find("input[name=email]:last").remove(); person.sync(); var emailCount = person.emails.length; </pre>

@emailCount@ is now @1@, reflecting the removal.

Call @sync()@ on a parcel after removing DOM elements.

<h2><a name="more_virtual">Virtual Field</a></h2>

A virtual field in jQuery.parcel is a jQuery object of a div, fieldset or other container like dom element, which contains fields in it's scope.

It represents a virtual part of parcel. You can treat a virtual field as a normal Field, that means you can call @state()@, @isDirty()@, @resetState()@, and do event operations like @bindState()@, @stateChange()@ on it.

Given this HTML:

<pre> <div id="person"> <div id="basicInfo"> <input type="text" name="firstname" value="Jane"/> <input type="text" name="lastname" value="Doe"/> ... </div> ... </div> </pre>

Then:

<pre> var person = $("#person").parcel(); var basicInfo = $("#basicInfo"); basicInfo.state(); #=> { firstname: "Jane", lastname: "Doe", ... } basicInfo.state({ firstname: "Mary" }); #=> { firstname: "Mary", lastname: "Doe", ... } basicInfo.resetState(); #=> { firstname: "Jane", lastname: "Doe", ... } basicInfo.bindState("#id_of_some_label", function(state){ /* compose a string from state */ }); basicInfo.stateChange(function(state){ /* play with the new state */ }); ... </pre>

The flexibility of virtual field makes the event wiring up much more expressive and easier.

<h1><a name="api">API Reference</a></h1> <h2><a name="api_parcel">Parcel</a></h2> <h3><a name="api_parcel_build">Build Parcel</a></h3> <p style="color:DarkCyan;font-size:18px;margin:10px">parcel([behaviour], [state])</p>

Returns: Parcel/array

For each element in jQuery, create a parcel and return the set of created parcels, return single parcel if only one element in jQuery object.

behaviour - optional, a function which will be mixed in after the parcel is created.

state - optional, the initial state of the parcel.

Common logic

Build with normal jQuery field

Build with array field

Build with Parcel as field

Build with virtual field

Build with behaviour

Build with initial state

Build multiple Parcels at once

<h3><a name="api_parcel_op">Parcel Operations</a></h3>

h4. sync([dom]) Returns: Parcel

create field(s) with the DOM element passed in or remove field(s) reflecting some DOM element is removed if DOM element is not provided.

dom - optional, newly cre

Related Skills

View on GitHub
GitHub Stars14
CategoryDesign
Updated6y ago
Forks2

Languages

JavaScript

Security Score

60/100

Audited on Aug 13, 2019

No findings