NAV
javascript

Introduction

Wishpond Landing Pages (also Popups and Forms) are fully functional out of the box and easily configurable with our WYSIWYG editor. If you really want to customise, however, we provide a powerful runtime environment.

Utility libraries

There are two libraries provided that can be used to manipulate the running page.

_wp()

This is our specialised version of jqlite, itself a minimal version of jQuery. This most likely contains all of the functionality you will need to modify the dom/styles/whatever.

wishpondApp

This object makes accessible all component and lifecycle functionality for the page itself. Anything you created in the editor is represented here and most of them can be interacted with.

Best Practices

Use wishpondApp.safe()

// Pass in a method
wishpondApp.on('pageStart', function() {
  wishpondApp.safe(function(){
    callFunctionThatDoesntExist()
  })
})

// Pass in a string to execute
wishpondApp.safe('console.log("this is safely executed")')

wishpondApp.safe(method)

wishpondApp.safe(code)

This method executes your custom code and ensures that it won’t cause the page to crash. If your custom code should encounter an error, a copy of the custom code will be logged to the console with the error making it much easier to figure out what went wrong instead of attempting to decipher completely arbitrary VM messages.

Use events, especially pageStart

// Can cause multiple errors
// 1. There might be no form on the page
// 2. There might not be a field called phone-number
wishpondApp.forms.first().field('phone-number').setValue('1800-123-456')

// Better, but still going to dump errors
_wp.safe(function() {
  wishpondApp.forms.first().field('phone-number').setValue('1800-123-456')
})

// Best: waiting for pageStart and checking that objects exist
wishpondApp.on('pageStart', function() {
  form = wishpondApp.forms.first();
  if (form) {
    field = form.field('phone-number');
    if (field) {
      field.setValue('1800-123-456');
    }
  }
})

This application has a rich library of events to tap into in order to customise the experience.

If the code you’re writing is attempting to modify anything on the page, the best time to run it is on pageStart. This event is triggered once all the standard code has run and the page is ready to present to the user for interaction. Since a landing page can contain multiple ‘pages’ (for instance, an entry page and a thank-you page), this event will fire once for each rendered page, ensuring that everything is up to date.

Skip jQuery

<script>
  // Create elements
  _wp(document.body).prepend('<div class="my-div">Hello world!</div>')

  // Set css on specific elements
  _wp('img').css({ opacity: 0.5 })

  // Show and hide elements
  _wp('p.hidden').show()

  // Listen for events
  _wp(window).on('click', function(event) { console.log(event) })
</script>

Most functions you could need are already available on the page with the _wp object.

See the _wp reference for a complete list of available methods.

Using jQuery Anyway

<script>
  // This will load jQuery and slow down load time unnecessarily
  $('#wp-html img').css({ opacity: 0.5 })

  // This does the same thing but doesn't require any extra loading
  _wp('#wp-html img').css({ opacity: 0.5 })

  // Same thing, using the recommended wishpondApp object
  wishpondApp.find('img').css({ opacity: 0.5 })
</script>

If you use jQuery or $ anywhere in your custom javascript we will automatically include a version of jQuery in the page. This slightly slows down loading and probably isn’t necessary so, whenever possible, just use _wp. It probably has everything you need and is already available.

Loading jQuery is only required if you want to make use of jQuery plugins or use jQuery animations or AJAX objects.

_wp

// starting by '<' returns a collection of DOM nodes from this code
// result: [<HTMLElement>]
_wp('<div class="foo">bar</div>');

// also accepts several objects at root level
// result: [<HTMLElement>, <HTMLElement>]
_wp('<div class="foo">bar</div><div class="bar">foo</div>');

// jqlite selectors returns collection by accepting pure css selectors
// jQuery uses sizzlejs to parse selectors
_wp('#some-id');
_wp('.some-class');
_wp('#wrapper .item');

_wp is our small utility object based on jqlite and very similar to jQuery in usage.

Handling Classes

Method Documentation
.addClass() jQuery.addClass()
.removeClass() jQuery.removeClass()
.toggleClass() jQuery.toggleClass()

Moving DOM Elements

Method Documentation
.append() jQuery.append()
.prepend() jQuery.prepend()
.before() jQuery.before()
.after() jQuery.after()
.wrap() jQuery.wrap()
.replaceWith() jQuery.replaceWith()
.detach() jQuery.detach()
.remove() jQuery.remove()

Getters / Setters

Method Documentation
.val() jQuery.val()
.html() jQuery.html()
.text() jQuery.text()
.contents() jQuery.contents()
.prop() jQuery.prop()
.attr() jQuery.attr()
.removeAttr() jQuery.removeAttr()
.data() jQuery.data()
.removeData() jQuery.removeData()
.empty() jQuery.empty()

Events

Method Documentation
.on() jQuery.on()
.off() jQuery.off()
.one() jQuery.one()
.trigger() jQuery.trigger()
.click() jQuery.click()
.focus() jQuery.focus()
.blur() jQuery.blur()

Relative Queries

Method Documentation
.first() jqlite.first()
.last() jqlite.last()
.find() jqlite.find()
.closest() jqlite.closest()
.parent() jQuery.parent()
.children() jQuery.children()

Miscelanea

Method Documentation
.css() jQuery.css()

wishpondApp

// Adding an element to the top of the page
wishpondApp.prepend('<p>Hello world</p>')

The running application is available as wishpondApp and is a specialised instance of _wp.

.component()

// To retrieve the controller for an existing component
wishpondApp.component('wpcButton_3') // => component controller

// To initialise a new component
wishpondApp.component('wpcButton_3', {}) // => component controller

Usage

wishpondApp.component(componentId)

Returns the controller for an already instantiated component or undefined if no controller exists. See Components for a list of available methods per controller.

wishpondApp.component(componentId, options)

Creates a new controller for the componentId specified with the supplied options hash. See Components for a list of instantiatable components and options.

.components()

// To retrieve controllers for all initialised videos
wishpondApp.components('.wpcVideo') // => [wpcVideo, ...]

Usage

wishpondApp.components(selector)

Returns an array of controllers for all elements matching the CSS selector. Only components with initialised controllers will be included in the results.

.deviceMode()

wishpondApp.deviceMode()
// => 'desktop'

Usage

wishpondApp.deviceMode()

Returns the current device mode (desktop, tablet, phone) based on the width of the window. The ranges are:

Window width Mode
≥ 1200px Desktop
≥ 768px, ≤ 1199px Tablet
≤ 767px Phone

.sourceURL()

wishpondApp.sourceURL()
// => 'https://www.wishpond.com/awesome-page'

Usage

wishpondApp.sourceURL()

If the page is embedded, it will return the url of the parent page. Otherwise it returns the url of the current page.

.is()

wishpondApp.is()
// => 'popup'

wishpondApp.is('popup')
// => true

Usage

wishpondApp.is()

Returns the type of the page. Types are listed in the table below.

wishpondApp.is(type)

Returns true if the current page is of type type.

Type Page
page The current page is a landing page (potentially embedded)
popup The current page is a popup
form The current page is a form (probably embedded)
call_to_action The current page is a call-to-action (probably embedded)

.isVisible()

wishpondApp.isVisible()
// => true

Usage

wishpondApp.isVisible()

Returns true if the page is currently visible. If the page is not embedded, this will always return true.

When the page is a popupthis will returntrue` if the popup is currently visible to the user.

When the page is a call-to-action or form, this will always return true.

.isEmbedded()

wishpondApp.isEmbedded()
// => true

Usage

wishpondApp.isEmbedded()

Returns true if the page is currently embedded in another page.

Popups, forms and calls-to-action will nearly always be embedded. Regular pages may or may not be embedded.

.hidePopup()

wishpondApp.hidePopup()
// => true

Usage

wishpondApp.hidePopup()

Only useful for popups, if the popup is currently visible this will hide it.

Will return true if the page is embedded and currently visible and will now be hidden. Otherwise, will return false.

.forms.find()

// Find by document-source ordering
wishpondApp.forms.find(0)
// => wpForm({ ... })

// Find by specific componentId
wishpondApp.forms.find('wpForm_3')
// => wpForm({ ... })

Usage

wishpondApp.forms.find(position)

Parameter Type Optional
position Number No

position represents the document-source order position of the form on the page. 0 will always represent the first form on the page but, thanks to the magic of CSS, it may not appear to be the first form on the page.

Will return the controller for the selected form.

wishpondApp.forms.find(componentId)

Parameter Type Optional
componentId String No

Will return the controller for the selected form.

.forms.first()

// Find the first form on the page
wishpondApp.forms.first()
// => wpForm({ ... })

// This is the same thing as
wishpondApp.forms.find(0)
// => wpForm({ ... })

Usage

wishpondApp.forms.first()

Will return the controller for the first (document-source-ordered) form on the page.

.forms.autosubmit()

// Submit the first valid form on the page
wishpondApp.forms.autosubmit()

Iterates through the forms on the page that have autosubmit enabled in the editor and submits the first valid one.

This method is useful if you’re using custom scripts to set form values after the page has initialised and want to try the autosubmit process again in case they’re now passing validation.

Usage

wishpondApp.forms.autosubmit()

Has no return value. Does not show validation states on the forms on the page.

If you want to catch when a form submits, use the participation events.

.forms.entryOpen()

// Returns whether or not entry is currently open on the forms
wishpondApp.forms.entryOpen()
// => true

// Close entry
wishpondApp.forms.entryOpen(false)
// => false

// Re-open entry
wishpondApp.forms.entryOpen(false)
// => true

See the wpForm controller for details on entryOpen.

Usage

wishpondApp.forms.entryOpen()

Will return true if entry is currently open on the forms on the page.

wishpondApp.forms.entryOpen(state)

Parameter Type Optional
state Boolean No

Will set the entryOpen state to state.

.leadProperties.fetch()

// Retrieve the lead properties from Wishpond Marketing Automation
wishpondApp.leadProperties.fetch().then(function(leadProperties) {
  console.log(leadProperties.get('name'))
});

// Once they've been fetched you can use them directly
wishpondApp.leadProperties.get('name')

// Or by merge tags
wishpondApp.mergeTags.parse('Hi, {{lead.name}}')

Fetches the lead properties from the server. Will only go to the server the first time it is called.

See .leadProperties.start() for what you’re actually after.

Usage

fetch()

Return value

Returns a promise that will be resolved when the server responds with the lead properties. The parameter passed to the resolve method is wishpondApp.leadProperties.

.leadProperties.get()

// .get() with no key will return all lead properties
wishpondApp.leadProperties.get()
// => { name: 'Bob' }

wishpondApp.leadProperties.get('name')
// => 'Bob'

Usage

get([key])

Parameter Type Optional
key String Yes

Return value

If key is omitted, the entire lead properties set will be returned. Otherwise the value stored at key will be returned.

.leadProperties.set()

wishpondApp.leadProperties.set({ name: 'Bob', age: 21 })
// => true

wishpondApp.leadProperties.set('name', 'Bob')
// => true

set(object)

Parameter Type Optional
object Object No

set(key, value)

Parameter Type Optional
key String No
value Whatever No

Return value

true if the call was correct and the data was added to the lead properties object, false if anything was wrong.

.leadProperties.start()

// Retrieve the lead properties from Wishpond Marketing Automation
wishpondApp.leadProperties.start()

// Once they've been fetched you can use them directly
wishpondApp.leadProperties.get('name')

// Or by merge tags
wishpondApp.mergeTags.parse('Hi, {{lead.name}}')

Fetches the lead properties from the server. Updates the stored lead properties after a participation event.

Usage

start()

.mergeTags.parse()

// Will use the default stored context
wishpondApp.mergeTags.parse('{{user.name}}')

// Will use the default stored context and the additional context
wishpondApp.mergeTags.parse('{{user.name}} drives a {{car}}', { car: 'Toyota' })

// A string with no merge tags included is still valid
wishpondApp.mergeTags.parse('This is still valid')

Usage:

parse(str[, additionalContext])

Parameter Type Optional
str String No
additionalContext Object Yes

If provided, the additionalContext is shallow merged with the stored context to allow you to override specific variables in certain circumstances.

The return value is always going to be a string, even if the last filter applied would have returned a collection or a numeric.

See Merge Tags for additional information on how merge tags are parsed.

.mergeTags.get()

// .get() with no key will return the entire stored context
wishpondApp.mergeTags.get()
// => { user: { name: 'Bob' } }

wishpondApp.mergeTags.get('user')
// => { name: 'Bob' }

wishpondApp.mergeTags.get('user.name')
// => 'Bob'

Usage

get([key])

Parameter Type Optional
key String Yes

Return value

If key is omitted, the entire stored context will be returned. Otherwise the value stored at key will be returned.

.mergeTags.set()

wishpondApp.mergeTags.set({ user: { name: 'Bob' } })
// => true

wishpondApp.mergeTags.set('user', { name: 'Bob' })
// => true

wishpondApp.mergeTags.set('user.name', 'Bob')
// => true

Usage

set(object)

Parameter Type Optional
object Object No

set(key, value)

Parameter Type Optional
key String No
value Whatever No

Return value

true if the call was correct and the data was added to the context, false if anything was wrong.

.mergeTags.del()

wishpondApp.mergeTags.del('user')
// => true

wishpondApp.mergeTags.del('user.name')
// => true

Usage

del(key)

Parameter Type Optional
key String No

Return value

true if the call was correct and the data was removed from the context, false if anything was wrong.

.mergeTags.refresh()

wishpondApp.mergeTags.refresh().then(function() {
  // All merge tags updated
})

Trigger all HTML embedded merge tags to update.

Usage

refresh()

Return value

A promise which will be resolved once all HTML embedded merge tags have been updated with the latest values.

.scrollTo()

// To a component ID
wishpondApp.scrollTo('wfcEmail_7')

// To a DOM selector
wishpondApp.scrollTo('button')
wishpondApp.scrollTo('#wfcEmail_7 input')

// To a DOM node
wishpondApp.scrollTo(document.getElementById('wfcEmail_7'))
wishpondApp.scrollTo(wishpondApp.find('#wfcEmail_7'))
wishpondApp.scrollTo(_wp('#wfcEmail_7'))

// To a component controller
wishpondApp.scrollTo(wishpondApp.forms.first())
wishpondApp.scrollTo(wishpondApp.component('wfcEmail_7'))

// To a form field
wishpondApp.scrollTo('phone-number')

// To a specific pixel position (not recommended)
wishpondApp.scrollTo(700)

// With a custom duration and chaining
wishpondApp.scrollTo('email', { duration: 250 }).then(function() {
  wishpondApp.component('email').inputs().focus()
})

Scroll the page (and potentially, the parent page) to the target.

target can be just about anything. Refer to the examples on the right.

While it is possible to roll your own scrolling system, using the built-in one guarantees much greater compatibility with the different publishing methods available for Wishpond pages.

Usage

scrollTo(target[, options])

See the examples on the right for a comprehensive list of potential targets.

Returns a promise that resolves once the animation is complete.

Options

All parameters are optional.

Parameter Type Default Description
duration Integer 1000 Time, in milliseconds, for the scroll to take
padTop Integer 0 Additional padding to apply to the scroll position
easing String easeInOutQuad Name of the easing strategy to use

.videos.find()

// Find by document-source ordering
wishpondApp.videos.find(0)
// => wpcVideo({ ... })

// Find by specific componentId
wishpondApp.videos.find('wpForm_3')
// => wpcVideo({ ... })

Usage

wishpondApp.videos.find(position)

Parameter Type Optional
position Number No

position represents the document-source order position of the video on the page. 0 will always represent the first video on the page but, thanks to the magic of CSS, it may not appear to be the first video on the page.

Will return the controller for the selected video.

wishpondApp.videos.find(componentId)

Parameter Type Optional
componentId String No

Will return the controller for the selected video.

.videos.first()

// Find the first video on the page
wishpondApp.videos.first()
// => wpcVideo({ ... })

// This is the same thing as
wishpondApp.videos.find(0)
// => wpcVideo({ ... })

Usage

wishpondApp.videos.first()

Will return the controller for the first (document-source-ordered) video on the page.

.videos.playAll()

// Set all videos on the page as playing
wishpondApp.videos.playAll()
// => true

Start all videos on the current page playing.

To play a single video, see the wpcVideo controller.

Usage

wishpondApp.videos.playAll()

.videos.pauseAll()

// Set all videos on the page as paused
wishpondApp.videos.pauseAll()
// => true

Set all videos on the current page as paused.

To pause a single video, see the wpcVideo controller.

Usage

wishpondApp.videos.pauseAll()

Components

There are two distinct classes of component controllers:

Prefix Purpose Example
wp, wpc Regular components wpForm_3, wpcVideo_19
wfc Form field components wfcEmail_11

Form field components are a superset of regular components, in that they have functionality specific to validation, error display, value setting, etc.

Any components that do not have controllers or usable methods on their controllers are excluded from this document.

All controllers

Name Description
wfcCheckbox A single checkbox.
wfcCheckboxGroup A group of checkboxes.
wfcDropdown A dropdown menu (select).
wfcFile A file uploader.
wfcRadioGroup A group of radio buttons.
wfcText All text input fields.
wfcTextarea Textarea input fields.
wpForm A form (wraps around many wfc components).
wpcButton A single button.
wpcFacebookComments A facebook comments box.
wpcIcon An icon.
wpcImage An image.
wpcMap A map.
wpcSocialButtons A social button bar.
wpcTimer A timer.
wpcVideo A video.

Common methods

These methods are available on all component controllers.

Method name Description
.componentId() Returns the componentId for the current component
.element() Returns the dom element for the current component

.componentId()

controller.componentId()
// => 'wfcText_42'

.componentId()

Returns the componentId for the given controller.

.element()

controller.element()
// => _wp([DOM node])

// You can manipulate the element as you would any _wp()-selected nodes
controller.element().css({ opacity: 0.5 })

.element()

Returns the root DOM node for the given component, wrapped in an _wp selector.

Form field methods

// Get the controller for the first input in the first form on the page.
controller = wishpondApp.forms.first().field(0);

These methods are common to all form fields controllers.

Method name Description
.getValue() If valid, returns the value set on the field
.setValue() Sets the value of the field
.enabled() Controls whether or not the input allows modification
.isValid() Is the current form field valid?
.showValidations() Shows and hides the validation messages on the field
.validate() Allows modification of the validation rules
.inputs() Returns a wrapped dom-selected collection of input fields

.getValue()

controller.getValue()
// => 'bob@example.com'

.getValue()

Returns the current value of the field if valid. If not valid, will return undefined.

.setValue()

controller.setValue('bob@example.com')
// => true

.setValue()

Sets the display value of the field. The field is still subject to validation, rules, however, so setting it to a value that is actually invalid will result in .getValue() returning undefined.

.enabled()

// Calling with no parameter will return the current enabled state
controller.enabled()
// => true

// Calling with false will disable the field
controller.enabled(false)
// => false

// Calling with true will re-enable the field
controller.enabled(true)
// => true

.enabled(value)

Parameter Type Description
value Boolean Optional. true if you want to enable the field, false to disable it. If not supplied it will return true if the field is currently enabled and false if the field is currently disabled.

.isValid()

controller.isValid()
// => true

.isValid()

Returns true if the field has no validations or has validations and passes them.

.showValidations()

// Calling with no parameter will show the validations
controller.showValidations()
// => true

// Calling with false will hide them
controller.showValidations(false)
// => false

.showValidations(enabled)

Parameter Type Description
enabled Boolean true if you want validations to display, false if you want to hide them. Defaults to true if not supplied.

Shows and hides per-field validation messages on the field. If the field has no validations or meets the validation, it will show no messages.

.validate()

// To get the field controller
field = wishpondApp.forms.first().field('email')

// To toggle all validations
field.validate(false)
field.validate(true)

// To check if a specific validation is in place
field.validate('required') // => true
field.validate('regex') // => false

// To remove specific validations
field.validate('regex', false)
field.validate('required', false)
field.validate('confirm', false)
field.validate('custom', false)

// To add a validation
field.validate('required', true, 'This field is required')
field.validate('regex', /^/, 'This field is invalid')
field.validate('confirm', 'email', 'This field does not match')
field.validate('custom', function(value) { return value === 'abc' }, 'This field is not "abc"')
field.validate('custom', function(value, controller) { return controller.inputs().val() === 'abc' }, 'This field is not "abc"')

.validate(true), .validate(false)

Enables or disables the validations for this field. Note that this will not make them visible if they are not already visible. See .showValidations() in order to controler the visibility of validation states.

.validate(type)

Returns true if that specific type of validation is enabled for this field.

See the table of types below.

.validate(type, false)

Removes any validations of that type from this field.

See the table of types below.

.validate(type, test, message)

Adds a validation of the given type with the supplied test to the field. The message is displayed next to the field if validations are enabled and showing and the field does not pass that specific validation.

Type Test Description
required true (Boolean) Requires that the field have a value as evaluated by _wp.isBlank(value)
regex RegExp or String Matches the current value of the field to the regular expression.
confirm Field identifier (String) Matches if the value is identical to the value of the specified field.
custom function Calls the supplied function with the current value and field controller.

See the examples to the right for usage.

.inputs()

controller.inputs()
// => _wp([DOM node])

// _wp methods can be called on the returned object
controller.inputs().css({ border: '1px red solid' })

.inputs()

Returns a wrapped DOM-selected collection of input fields.

wfcText

The following components all share the same controller:

In addition to the common methods and the form field methods, these controllers support this method:

.formatter()

// Calling with no parameter will show the validations
controller.formatter()
// => true

// Calling with false will hide them
controller.formatter(false)
// => false

// Calling with a method will set the formatter to be that method
//
// The formatter receives a string, and the value of the input will be set to
// whatever the formatter returns. In this case, if the user specifies a phone
// number with a leading 0, the formatter will replace that 0 with +64, the
// country code for New Zealand.
form.field('phone-number').formatter(function(str) {
  return (str || '').replace(/^0/, '+64');
})

.formatter()

Returns true if there is a formatter applied, false otherwise.

.formatter(false)

Parameter Type Description
callback Boolean If false, will disable any applied formatter.

.formatter(callback)

Parameter Type Description
callback Method Sets the formatter callback to the supplied method.

The callback method will be called whenever the value for the field changes and it will receive as a parameter the current value of the field. The final value for the field will be whatever the callback returns.

wpForm

// This is a contrived example of interacting with the
// form controller. It will submit the first form on
// the page if it is valid, otherwise it will put focus
// on the first invalid field in that form.

// Get the form controller
form = wishpondApp.forms.first();
// => wfcText()

// Check validity
if (form.isValid()) {
  // Submit the form
  form.submit();
  // => true
}
else {
  // Focus the first invalid field
  var focusSet = false;
  _wp(form.fields()).each(function() {
    if (!focusSet && !this.isValid()) {
      focusSet = this;
      this.inputs().focus();
    }
  })
}
Method name Description
.field() Returns the controller for a single field
.fields() Returns the controllers for all fields in the form
.buttons() Returns the controllers for all buttons in the form
.isValid() Returns whether or not the form passes validations
.showValidations() Shows and hides the validation messages on the form
.submit() Submits the form
.autosubmit() Submits the form if valid
.enabled() Controls whether or not the form allows modification
.entryOpen() Controls whether or not the form allows entry
.toObject() Converts all valid form fields to an object
.toParamAliases() Converts all valid form fields to an object, using the param aliases as keys
.toPrefillURL() Converts the current state of the form into a prefill URL

.field()

// Select by componentId
form.field('wfcFirstname_3')
// => wfcText()

// Select by param alias
form.field('first-name')
// => wfcText()

// Select by position in the form
form.field(1)
// => wfcText()

// Select by CSS selector
form.field('#wfcFirstname_3')
// => wfcText()
form.field('.wfcFirstname')
// => wfcText()

Returns the matching form field controller. Returns undefined if no controller is found.

.field(componentId)

Parameter Type Description
componentId String Internal id of the component. Takes the form <className>_<randomNumber>.

.field(paramAlias)

Parameter Type Description
paramAlias String Identifier used in prefilled URLs. Can be changed in the editor.

.field(position)

Parameter Type Description
position Integer Source-ordered position of the field in the form.

.field(selector)

Parameter Type Description
selector String Any CSS selector that will resolve to a div with the class wfcField.

If multiple fields match the selector, only the first controller will be returned.

.fields()

form.fields()
// => [wfcText(), wfcDropdown(), ...]

.fields()

Returns all field controllers from the form in a document source-ordered array.

.buttons()

form.buttons()
// => [wpButton(), ...]

.buttons()

Returns all button controllers from the form in a document source-ordered array.

.isValid()

form.isValid()
// => true

.isValid()

Returns true if all form field controllers in the form are valid (that is, they have no validation requirements or they meet any specified validation requirements).

.showValidations()

// Calling with no parameter will show the validations
form.showValidations()
// => true

// Calling with false will hide them
form.showValidations(false)
// => false

.showValidations(enabled)

Parameter Type Description
enabled Boolean true if you want field validations to display, false if you want to hide them. Defaults to true if not supplied.

Shows and hides per-field validation messages on the supplied form. Fields that have no validations and fields that meet the validations will show no messages.

.submit()

// Submit a form and see what happens
form.submit()

// The participation lifecycle has many events that can be attached to
// though you do need to listen for these events before submitting the form
wishpondApp.on('participationSuccess', function(event) {
  console.log('Participation was successful')
})
form.submit()

.submit()

Submits the form. Returns true if the form was valid and a participation was started, returns false if the form is invalid or if there is already a participation in progress.

The preferred mechanism for interacting with the participation is through the exposed events.

See participationStart for details on the participation lifecycle.

.enabled()

// Calling with no parameter will return the current enabled state
form.enabled()
// => true

// Calling with false will disable the form
form.enabled(false)
// => false

// Calling with true will re-enable the form
form.enabled(true)
// => true

.enabled(value)

Parameter Type Description
value Boolean Optional. true if you want to enable the form, false to disable it. If not supplied it will return true if the form is currently enabled and false if the form is currently disabled.

.entryOpen()

.entryOpen(value)

Parameter Type Description
value Boolean Optional. See .enabled() for details.

Enables or disables the form as per .enabled() but also sets an overlay disabled message.

.toObject()

form.toObject()
// => { 'first-name': 'Bob', 'email': 'bob@example.com' }

.toObject()

Returns all valid form fields in an object with specified param aliases as an object.

It is possible for form fields to not have specified param aliases, however, and to therefore be missed out from this object. Passing in false as the parameter will cause it to use the fieldId, an internal Wishpond representation of the field, instead.

.toPrefillURL()

form.toPrefillURL()
// => "https://www.wishpond.com/lp/3/?phone-number=1234567"

.toPrefillURL()

Returns a URL that maps the current state of the form with the correctly filled in fields that also happen to have defined param aliases.

wpcButton

In addition to the common methods, this controller supports this method:

.enabled()

// Calling with no parameter will return the current enabled state
button.enabled()
// => true

// Calling with false will disable the button
button.enabled(false)
// => false

// Calling with true will re-enable the button
button.enabled(true)
// => true

.enabled(value)

Parameter Type Description
value Boolean Optional. true if you want to enable the button, false to disable it. If not supplied it will return true if the button is currently enabled and false if the button is currently disabled.

wpcVideo

In addition to the common methods, this controller supports these methods:

.play()

.pause()

Events

// To listen for Wishpond-specific events, use wishpondApp
wishpondApp.on('pageStart', function(event, pathFragment, page) {
  console.log('pageStart received', pathFragment, page)
})

// All event parameters are optional. If you don't care about the parameters, you can skip them:
// wishpondApp.on('pageStart', function() {
// wishpondApp.on('pageStart', function(event) {
// wishpondApp.on('pageStart', function(event, pathFragment) {

// To listen to regular DOM events, use _wp().on()
_wp(window).on('resize', function(event) {
  //
})

Listing for events on wishpondApp will enable your custom javascript to interface with the running page.

componentStart

wishpondApp.on('componentStart', function(event, componentController) {
  console.log("Component started", componentController);
})

This event is fired after a component has been initialised.

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The controller for the newly initialised component

componentStop

wishpondApp.on('componentStop', function(event, componentController) {
  console.log("Component stopped", componentController);
})

This event is fired after a component has been stopped and all listeners detached..

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The controller for the now-stopped component

deviceModeChange

wishpondApp.on('deviceModeChange', function(event, deviceMode, previousDeviceMode) {
  console.log("Device mode changed", deviceMode, previousDeviceMode);
})

This event is fired after the device mode has been changed.

The device mode is an internal moniker representing the available screen size and likely device type. Values are:

Canceling this event has no effect.

Parameter Type Description
event Event
deviceMode String The current device mode
previousDeviceMode String The previous device mode (if any)

mergeTagsChange

wishpondApp.on('mergeTagsChange', function(event) {
  console.log("Merge tags have been changed", wishpondApp.mergeTags.get());
})

This event is fired after changes have been made to the stored merge tags context and all automatic merge tags have been updated.

Canceling this event has no effect.

Parameter Type Description
event Event

pageAdd

wishpondApp.on('pageAdd', function(event, page) {
  console.log("Page added", page);
})

This event is fired after a page has been added to the router.

Canceling this event has no effect.

Parameter Type Description
event Event
page Wishpond.V2.Page The page object being rendered

pageChange

wishpondApp.on('pageChange', function(pathFragment, page) {
  console.log("Starting page change", pathFragment);

  // Cancel the event to stop the page change
  event.preventDefault();
})

This event is fired before the page is changed.

Canceling this event will stop the page change from happening.

Parameter Type Description
event Event
pathFragment String The path fragment that triggered navigation to this page
page Wishpond.V2.Page The page object being rendered

pageNotFound

wishpondApp.on('pageNotFound', function(event, pathFragment) {
  console.log("Failed to navigate to", pathFragment);
})

This event is fired when a page change has happened (either in code or through clicking on a link) and the router is unable to find a corresponding page to render.

Canceling this event has no effect.

Parameter Type Description
event Event
pathFragment String The path fragment that triggered navigation to this page

pageStart

wishpondApp.on('pageStart', function(event, pathFragment, page) {
  console.log("Navigated to", window.location.href);
})

This event is fired after:

Canceling this event has no effect.

Parameter Type Description
event Event
pathFragment String The path fragment that triggered navigation to this page
page Wishpond.V2.Page The page object being rendered

pageStop

wishpondApp.on('pageStop', function(event) {
  console.log("Current page is being stopped");
})

This event is fired after a pageChange has been fired but before pageStart on the new page. It is used to tell any components on the current page to detach event listeners or unsubscribe from services to avoid memory leaks.

Canceling this event has no effect.

Parameter Type Description
event Event

participationStart

wishpondApp.on('participationStart', function(event, componentController) {
  console.log('Participation started from', componentController)
})

This event is fired when a participation attempt is about to be made. The attempt could be fired by:

If fired by a form (either manual or auto submission) this event will be fired after validationSuccess. Since no validation is performed on button conversions there is no corresponding event.

Canceling this event will stop the participation attempt from being made.

Parameter Type Description
event Event
componentController Controller The component controller that triggered the participation event

Lifecycle

An example participation from a form submission would look like this:

  1. validationChange as the user enters information into the form and then fields are either valid or not.
  2. validationSuccess as the user submits the form. validationFail could also be fired if the form is not valid, at which point the process stops.
  3. participationStart before the participation attempt takes place.
  4. participationSuccess after the participation attempt succeeds. participationFail could also be fired if, for any reason, participation was denied.
  5. participationComplete after the participation attempt is finalised. Fires regardless of the success or failure of the attempt.

participationSuccess

wishpondApp.on('participationSuccess', function(event, componentController) {
  console.log('Participation succeeded from', componentController)
})

This event is fired after a participation attempt succeeds and the local data stores have been updated but before the default participation action has been triggered.

The default participation action is whatever is defined in the editor. It includes (but is not limited to):

Canceling this event will stop the default participation action from being performed. It is then up to you to inform the user that the participation was successful.

Parameter Type Description
event Event
componentController Controller The component controller that triggered the participation event

Lifecycle

See participationStart for details on the participation lifecycle.

participationFail

wishpondApp.on('participationFail', function(event, componentController) {
  console.log('Participation failed from', componentController)
})

This event is fired after a participation attempt fails.

Failure could be caused by a network error or by server-side rejection of the participation attempt.

Server-side rejection reasons include (but are not limited to):

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The component controller that triggered the participation event

Lifecycle

See participationStart for details on the participation lifecycle.

participationComplete

wishpondApp.on('participationComplete', function(event, componentController, success) {
  console.log('The participation event has completed')
})

This event is fired after a participation attempt is completed, either with success or failure. If the attempt was successful, this event fires after the default participation action has been performed.

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The component controller that triggered the participation event
success Boolean true if the participation completed successfully

Lifecycle

See participationStart for details on the participation lifecycle.

validationChange

wishpondApp.on('validationChange', function(event, componentController, isValid) {
  console.log('Validation changed on', componentController, isValid)
})

This event is fired after a field changes validation state (either from valid to invalid or from invalid to valid).

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The form field component controller that has changed validation state
isValid Boolean True if the field is valid

validationSuccess

wishpondApp.on('validationSuccess', function(event, componentController) {
  console.log('Form is valid', componentController)
})

This event is fired after a form becomes valid and ready for submission.

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The form controller that has just become valid

validationFail

wishpondApp.on('validationFail', function(event, componentController) {
  console.log('Form is invalid', componentController)
})

This event is fired after a form becomes invalid and is no longer ready for submission.

Canceling this event has no effect.

Parameter Type Description
event Event
componentController Controller The form controller that has just become invalid

visibilityChange

wishpondApp.on('visibilityChange', function(event, visible) {
  if (visible) {
    console.log('Visible')
  }
  else {
    console.log('No longer visible')
  }
})

This event is fired after a popup is made visible to the user and after it’s removed from view.

This event will only fire on popups.

Canceling this event has no effect.

Parameter Type Description
event Event
visible Boolean true if the popup is now visible, false if the popup is now hidden.

Merge Tags

Wishpond provides a subset of the Liquid templates functionality that can be accessed either through specially-crafted HTML elements or javascript.

The main differences to note are that we do not support any control-flow or iteration tags. If that functionality is required for a page it can be faked with minimal custom javascript.

HTML

<!-- In the editor -->
<p>Hello, {{user.name}}.</p>

<!-- Output -->
<p>Hello, <span merge-tag="{{user.name}}"></span>.</p>

Merge tags inserted in the editor are converted to the special format used by wishpondApp.

Javascript

// Interpolate the string using only existing data
wishpondApp.mergeTags.parse('Hello, {{user.name}}')

// Pass in additional data
wishpondApp.mergeTags.parse('Hello, {{organisation.name}}', { organisation: { name: 'Global Corp.' }})

// Adding HTML to the document with merge tags included
wishpondApp.prepend('<p>Hello, <span merge-tag="{{user.name}}"></span></p>').mergeTags.refresh()

Merge tags can be interpolated at any time calling wishpondApp.mergeTags.parse()

If inserting HTML into the page with merge tags included, be sure to use a span with the merge-tag attribute.

Filters

<!-- In HTML -->
<p>Hello, {{user.email|split:'@'|first}}</p>
// In javascript
wishpondApp.mergeTags.parse('Hello, {{user.email|split:'@'|first}}')

Filters are modifiers applied to a given value.

Any number of filters can be applied to produce the desired result. They are chained with the | (pipe) character.

Some filters have no parameters, others have optional parameters and some have required parameters. The first parameter is delimited by the : (colon) character and subsequent parameters are separated by , (comma).

See Filters for a list of all available filters and their parameters.

Variables

// Passing in a constant
wishpondApp.mergeTags.parse("{{'Hello world'}}");

// Passing in a variable
wishpondApp.mergeTags.parse("{{text}}", { text: 'Hello world' });

// If the variable was already set, we don't need to pass in additional context
wishpondApp.mergeTags.set('text', 'Hello world');
wishpondApp.mergeTags.parse("{{text}}");

// Variables and constants can also be used as parameters on filters in any combination
wishpondApp.mergeTags.parse("{{'Hello world'|replace:from,to}}", { from: 'He', to: 'Wa'});
wishpondApp.mergeTags.parse("{{text|replace:'He','Wa'}}", { text: 'Hello world' });

// All together now
wishpondApp.mergeTags.set({ text: 'Hello world', from: 'He', to: 'Wa'});
wishpondApp.mergeTags.parse("{{text|replace:from,to}}");

Variables can be Numeric (123, 1.23, etc), Collections ([1,2,3], {a:'b'}) or Strings ('abc').

See .mergeTags.get(), .mergeTags.set() and .mergeTags.del() for more information on storing variables for use in merge tags.

Filters

These filters are applicable to all Merge Tags used anywhere in the application.

Strings

Name Description
append Affix a string to a text
capitalize Converts text to Capital case
default Uses a fallback text if the supplied variable is blank
downcase Converts text to lower case
escape Convert HTML to entities for display
escape_once escape, but only once
newline_to_br Convert any newlines to HTML line breaks
prepend Prefix a string to a text
remove Remove all instances of a string from a text
remove_first Remove the first instance of a string from a text
replace Replace all instances of a string in a text
replace_first Replace the first instance of a string in a text
split Split a string into a collection
strip_html Remove any HTML from a text
strip_newlines Remove any newlines from a text
truncate Truncate a text to a character count
truncatewords Truncate a text to a word count
upcase Converts text to UPPER CASE

Numerics

Name Description
divided_by Divide by the supplied value
minus Subtract the supplied value
modulo Remainder after division by the supplied value
plus Add the supplied value
times Multiply by the supplied value

Dates

Name Description
date Converts a timestamp, date string or date object into a specified date format

Collections

Name Description
first Select the first element
join Combine all elements into a string
last Select the last element
reverse Reverse all elements in the collection
sort Sort all elements in the collection alphabetically

append

wishpondApp.mergeTags.parse("{{'Hello'|append:' world'}}")
// => "Hello world"

Suffix the supplied value to the given string.

Parameter Optional Type Default
string No String None

capitalize

wishpondApp.mergeTags.parse("{{'hello world'|capitalize}}")
// => "Hello world"

Capitalise the first letter in the supplied string.

date

wishpondApp.mergeTags.parse("{{'now'|date:'%Y-%m-%d'}}")
// => '2016-10-12'

wishpondApp.mergeTags.parse("{{'now'|date:'%A, %b %d'}}")
// => 'Wednesday, Oct 12'

wishpondApp.mergeTags.parse("{{'now'|date:'%A, %d %b %Y %l:%M %p'}}")
// => 'Wednesday, 12 Oct 2016  9:14 AM'

wishpondApp.mergeTags.parse("{{timestamp|date:'%Y-%m-%d'}}", { timestamp: new Date() })
// => '2016-10-20'

Convert the supplied value to a given date format.

Date formats are specified in strftime format.

A special value is the string "now" which is converted to a date object representing the moment the tag was parsed. It will only be updated with the new now when the merge tags are changed or refresh() is called so avoid listing with to-the-second precision or use setInterval to update the value when necessary.

Parameter Optional Type Default
format No String None

Compatibility

_s('moment', 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.15.2/moment.min.js')
.then(function() {
  // Use moment to parse the arbitrary date string
  var milliseconds = moment("2010-10-20 4:30 +0000", "YYYY-MM-DD HH:mm Z").valueOf()
  wishpondApp.mergeTags.set('myDate', milliseconds)
})

Javascript support for parsing strings into date objects is notoriously bad.

Internet Explorer sets the baseline with the format yyyy-mm-ddYhh:mm:ss. While other browsers will accept more formats, that is the most compatible. If you can’t format your dates as unix or unix-ms timestamps (eg., 1477328439 or 1477328439000) and you can’t format your timestamp as yyyy-mm-ddYhh:mm:ss then we suggest that you load the moment library for date parsing as per the example on the right.

divided_by

wishpondApp.mergeTags.parse("{{6|divided_by:3}}")
// => "2"

Divide by the supplied value.

Parameter Optional Type Default
value No Numeric None

default

wishpondApp.mergeTags.parse("{{existing|default:'fallback'}}", { existing: 'Hello!'})
// => "Hello!"

wishpondApp.mergeTags.parse("{{missing|default:'fallback'}}", { existing: 'Hello!'})
// => "fallback"

Uses the fallback value if the supplied value is blank.

Parameter Optional Type Default
fallback No Anything None

downcase

wishpondApp.mergeTags.parse("{{'HELLO world'|downcase}}")
// => "hello world"

Convert the entire string to lower case

escape

wishpondApp.mergeTags.parse("{{'<h1>Hello world</h1>'|escape}}")
// => "&lt;h1&gt;Hello world&lt;/h1&gt;"

Convert any HTML specific characters so that they’re safe for display.

escape_once

wishpondApp.mergeTags.parse("{{'&lt;h1&gt;Hello world</h1>'|escape_once}}")
// => "&lt;h1&gt;Hello world&lt;/h1&gt;"

Convert any HTML specific characters so that they’re safe for display, but ignoring any characters that are already part of HTML entities.

first

wishpondApp.mergeTags.parse("{{collection|first}}", { collection: [1,2,3] })
// => "1"

Return the first element in any collection.

join

wishpondApp.mergeTags.parse("{{collection|join}}", { collection: [1,2,3] })
// => "1 2 3"

wishpondApp.mergeTags.parse("{{collection|join:', '}}", { collection: [1,2,3] })
// => "1, 2, 3"

Combine the elements in any collection into a string.

Parameter Optional Type Default
joinString Yes String “ ” (single space)

last

wishpondApp.mergeTags.parse("{{collection|last}}", { collection: [1,2,3] })
// => "3"

Return the last element in any collection.

minus

wishpondApp.mergeTags.parse("{{6|minus:3}}")
// => "3"

Subtract the supplied value.

Parameter Optional Type Default
value No Numeric None

modulo

wishpondApp.mergeTags.parse("{{7|modulo:3}}")
// => "1"

Remainder after division by the supplied value.

Parameter Optional Type Default
value No Numeric None

newline_to_br

wishpondApp.mergeTags.parse("{{text|newline_to_br}}", { text: "Hello\nworld" })
// => "Hello<br/>world"

Remainder after division by the supplied value.

Parameter Optional Type Default
value No Numeric None

plus

wishpondApp.mergeTags.parse("{{6|plus:3}}")
// => "9"

Add the supplied value.

Parameter Optional Type Default
value No Numeric None

prepend

wishpondApp.mergeTags.parse("{{'world'|prepend:'Hello '}}")
// => "Hello world"

Affix the supplied value to the given string.

Parameter Optional Type Default
string No String None

replace

wishpondApp.mergeTags.parse("{{'Hello world'|replace:'l','+'}}")
// => "He++o wor+d"

wishpondApp.mergeTags.parse("{{'Hello world'|replace:'llo','eey'}}")
// => "Heeey world"

Replace all instances of search with replacement.

Parameter Optional Type Default
search No String None
replacement No String None

replace_first

wishpondApp.mergeTags.parse("{{'Hello world'|replace_first:'l','+'}}")
// => "He+lo world"

wishpondApp.mergeTags.parse("{{'Hello world'|replace_first:'llo','eey'}}")
// => "Heeey world"

Replace only the first instance of search with replacement.

Parameter Optional Type Default
search No String None
replacement No String None

remove

wishpondApp.mergeTags.parse("{{'Hello world'|remove:'l'}}")
// => "Heo word"

wishpondApp.mergeTags.parse("{{'Hello world'|remove:'Hel'}}")
// => "lo world"

Remove all instances of search.

Parameter Optional Type Default
search No String None

remove_first

wishpondApp.mergeTags.parse("{{'Hello world'|remove_first:'l'}}")
// => "Helo world"

wishpondApp.mergeTags.parse("{{'Hello world'|remove_first:'Hel'}}")
// => "lo world"

Remove only the first instance of search.

Parameter Optional Type Default
search No String None

reverse

wishpondApp.mergeTags.parse("{{collection|reverse}}", { collection: [1,2,3] })
// => "3,2,1"

Reverse the order of any collection.

sort

wishpondApp.mergeTags.parse("{{collection|sort}}", { collection: [2,3,1,'a','A'] })
// => "1,2,3,A,a"

Sort any collection alphanumerically. The sort order is:

split

wishpondApp.mergeTags.parse("{{'Hello     world'|split}}")
// => "Hello,world"

wishpondApp.mergeTags.parse("{{text|split}}", { text: "Hello\nworld" })
// => "Hello,world"

wishpondApp.mergeTags.parse("{{'Hello world'|split:'l'}}")
// => "He,,o wor,d"

wishpondApp.mergeTags.parse("{{'Hello world'|split:delimiter}}", { delimiter: /[l]+/ })
// => "He,o wor,d"

Split a string on any delimiter.

Parameter Optional Type Default
delimiter Yes String/Regex /\s+/ (any amount of whitespace)

strip_html

wishpondApp.mergeTags.parse("{{'<h1>Hello world</h1>'|strip_html}}")
// => "Hello world"

Remove any HTML markup from the supplied string.

strip_newlines

wishpondApp.mergeTags.parse("{{text|strip_newlines}}", { text: "Hello\nworld" })
// => "Helloworld"

Remove any HTML markup from the supplied string.

times

wishpondApp.mergeTags.parse("{{6|times:3}}")
// => "18"

Multiply by the supplied value.

Parameter Optional Type Default
value No Numeric None

truncate

wishpondApp.mergeTags.parse("{{'Hello world'|truncate}}")
// => "Hello world"

wishpondApp.mergeTags.parse("{{'Hello world'|truncate:3}}")
// => "Hel..."

wishpondApp.mergeTags.parse("{{'Hello world'|truncate:3,'-'}}")
// => "Hel-"

Shorten a string to a specified number of characters. A string that is less than that number of characters long will be left untouched.

Parameter Optional Type Default
length Yes Numeric 50
ellipsis Yes String “…”

truncate_words

wishpondApp.mergeTags.parse("{{'Hello world'|truncate_words}}")
// => "Hello world"

wishpondApp.mergeTags.parse("{{'Hello world'|truncate_words:1}}")
// => "Hello..."

wishpondApp.mergeTags.parse("{{'Hello world'|truncate_words:1,'-'}}")
// => "Hello-"

Shorten a string to a specified number of words. A string that is less than that number of words long will be left untouched.

Parameter Optional Type Default
length Yes Numeric 15
ellipsis Yes String “…”

upcase

wishpondApp.mergeTags.parse("{{'hello world'|upcase}}")
// => "HELLO WORLD"

Convert the entire string to upper case.

Beta

This functionality has not been finalised yet and is still subject to changed. Don’t build anything on it yet.

Custom Pages

html = '<h1>Completely custom page!</h1>'

new Wishpond.V2.Page.Local(wishpondApp, /^custom(?:\/)?$/, {
  page: {
    html: html,
    js: function() { console.log("Custom script executed") },
    css: 'h1 { color: red; }'
  },
  slug: 'custom'
});

Additional pages can be added to a running application in the custom javascript.

Example use

A merchant could fake an entire static website by registering additional pages with content/forms as necessary and adding a menu to each page with the pageStart event in their custom javascript. The user would then be able to click around the site completely unaware that was, once upon a time, a simple landing page.

Example use

A merchant could desire two distinct pages to redirect a user to after they have participated in an landing page. By intercepting participationSuccess, their custom javascript could add the desired page to the application and run_javascript on the form could navigate the user to that page.

Alternatively, it may make sense to make the participationSuccess event cancelable, at which point the post-participation code would be skipped and it would be up to the custom javascript to ensure a sane experience for the user.

Example use

A merchant could add a consistent /contact-us page to all of their landing pages by adding it to their global custom javascript.