December update of Behavior/Delegator (drop in or not?)

13 views
Skip to first unread message

Rolf-nl

unread,
Jan 6, 2014, 4:18:13 PM1/6/14
to clien...@googlegroups.com
There's a big update to Behavior (or especially Delegator I think, scanning the commits). I just dropped it in a project and it seems "everything" is still working, still testing though. Is this expected or should I pay attention the specific areas, because in some places it looks like a rewrite of the main files :) I'm also using a bunch of Bootstrap-related behaviors/delegators and even the custom ones (or modified out-of-the-box ones) seem to work without problems.

So, before I'm adding or implementing new features I'd like to make sure I'm not overlooking any core issues I might stumble upon after a few weeks when I'm adding more & more "new-Behavior" code.

Is this a question or am I not making sense? lol...

Thumbs up for the continuous work! I'm excited to implement the new triggers, very handy and cleaner code..!

Rolf

Aaron Newton

unread,
Jan 6, 2014, 5:00:43 PM1/6/14
to Clientcide
Should be a drop in; it’s almost entirely additional stuff, not changes to pre-existing stuff. The big changes are these:

### Conditionals

Delegator also allows any trigger's options to include conditionals that will prevent or allow the trigger from being invoked if they match. These conditionals are run at event time, allowing you to program your UI for different states. Delegator provides two conditionals - `if` and `unless`. In theory this could be extended to include others like less than or greater than at some point.

#### Examples

<a data-trigger="foo" data-foo-options="
'if': {
'self::hasClass': ['foo'] //could also just be 'foo'; use an array for multiple arguments
}
">...</a>

<a data-trigger="foo" data-foo-options="
'unless': {
'self::hasClass': ['foo']
}
">...</a>

Both the examples above reference the `foo` trigger and specify conditionals. The first one uses the special `if` conditional and requires that the element itself has the class "foo" (which it doesn't), and thus the trigger will not fire. The second one is nearly identical but uses the special `unless` conditional, which does the same check but verifies that it's NOT true, so that one will.

There's a more verbose version of these conditionals that looks like this:

<a data-trigger="foo" data-foo-options="
'if': {
'target': 'self',
'method': 'hasClass',
'arguments': ['foo'],
'value': true
}
">...</a>

Here we explicitly name the target (`self`), the method invoked on that element (`hasClass`) - this can be any element method, the arguments passed to that method, and the value we expect it to return. The previous examples are just shorthands that are parsed into this more verbose format.

### Multiple Triggers

Delegator also provides a custom trigger called "multi" which allows a single element to invoke triggers on OTHER elements each with its own options. This allows you to have a single element that the user clicks and then it hides some elements, adds classes to others, etc.

#### Example

<a data-trigger="multi" data-multi-triggers="
[
{
'.foo::someTrigger': {
'arg':'blah'
}
},

'.bar::someOtherTrigger',

{
'.baz::yetAnotherTrigger': {
'if':{
'self::hasClass': 'foo'
}
}
}
]
"></a>

Here we have 3 different Delegator triggers we are invoking when the user clicks our link.

* The first is the "someTrigger" trigger which is invoked on any child element with the "foo" class. This one has a configuration - the options for the trigger. See important note below about how these are used.
* The second one just invokes the "someOtherTrigger" on any child element with the "bar" class.
* The third invokes the "yetAnotherTrigger" on any element with the "baz" class *provided that it also has the "foo" class*.

#### Important Notes

* The configuration specified this way are passed to [BehaviorAPI][]'s `setDefault` method. This means that if the target element has its own configuration for these triggers that the configuration options specified on the element win.
* Conditionals evaluated in these triggers are evaluated on the targets, not the element where they are specified. In other words, in the last example above where there's a check to see if `'self::hasClass': 'foo'"`, `self` will reference each matched element for `.baz`. These options specified here are projected on each matched element as if the trigger were there.
* If you express more than one conditional statement in your `if` or `unless` object, each is evaluated and the condition **fails** if *any* of them do. In this example, each statement in the `unless` object is evaluated. If *any* are `true` (because it's an `unless` statement) the trigger is not invoked.

<a data-trigger="foo" data-foo-options="
'unless': {
'self::hasClass': ['foo'],
'.someElement::hasClass': ['bar']
}
">...</a>

* You can, if you like, still specify a conditional for the "multi" trigger. This means the entire list of triggers will be ignored if your condition fails. Example:

<a data-trigger="multi" data-multi-options="
'triggers': [
'.foo::someTrigger',
'.bar::someOtherTrigger'
],
'unless': {
'self::hasClass': 'whatever'
}
"></a>

### Switches

Finally, Delegator offers a special trigger called a `switch`. These allow you to define multiple sets of triggers to execute when a condition is met. If the user clicks this button and some radio button is selected, execute these triggers on THAT group of elements, else execute these OTHER triggers on these OTHER elements.

There are two types of switches: `first` and `any`. The `first` switch iterates over your switch groups (in the order they are declared) and executes the first group whose condition is `true`, while the `any` switch iterates over all the trigger groups, executing any whose condition is true. As with all triggers, a group with no condition is treated as one that is `true` and executed.

#### Examples

<a data-trigger="first" data-first-switches="[
{
'if': {
'div.foo::hasClass':['baz']
},
triggers: [
'.foo::trigger1'
]
},
{
'unless': {
'div.foo::hasClass':['baz']
},
triggers: [
'.foo::trigger2'
]
},
{
triggers: [
'.foo::trigger3'
]
}
]">...</a>

In the above example, Delegator iterates over the array of trigger groups defined in the `first` switches. When it finds one that is valid, it runs the triggers defined within it. The last group in the example has no condition and is essentially treated as the default case in the eventuality that none of the previous are `true`. (Note that in this example, because the first two in the group are the same condition with one an `if` and the other an `unless`, one of them *has* to be true.)

<a data-trigger="any" data-any-switches="[
{
'if': {
'div.foo::hasClass':['baz']
},
triggers: [
'.foo::trigger1'
]
},
{
'unless': {
'div.foo::hasClass':['baz']
},
triggers: [
'.foo::trigger2'
]
},
{
triggers: [
'.foo::trigger3'
]
}
]">...</a>

In this example, which is nearly identical to the first one except the switch type is `any` instead of `first`, Delegator iterates over all of the trigger groups and executes each if their conditional is `true`. While the `first` example would execute one of the first two in the group (because they are opposites in the example) and stop, the `any` example will execute one of the first two (whichever is `true`) AND the last one.

#### Conditionals with Switches

Note that, as with any trigger, you can have a conditional for the switch itself:

<a data-trigger="any" data-any-options="
'switches': [
{
'if': {
'div.foo::hasClass':['baz']
},
triggers: [
'.foo::trigger1'
]
},
{
triggers: [
'.foo::trigger3'
]
}
],
'unless': {
'.foo::hasClass': ['bazoo']
}
">...</a>


--
You received this message because you are subscribed to the Google Groups "Clientcide" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clientside+...@googlegroups.com.
To post to this group, send email to clien...@googlegroups.com.
Visit this group at http://groups.google.com/group/clientside.
For more options, visit https://groups.google.com/groups/opt_out.

Reply all
Reply to author
Forward
0 new messages