Table of Contents
In LZX, a constraint is an attribute whose value is a function of one or more other attribute's value(s).
Constraints help you quickly create dependencies without writing a lot of code. You can specify that certain views are the same size or positioned relative to one another. Specific elements can appear only under certain conditions; and those conditions may be declared with a simple expression. Constraints may be used for non-visual attributes as well.
| ![[Note]](images/note.png) | Note | 
|---|---|
| You can only use constraints with read/write attributes. | 
Constraints may be created as follows:
These are described in turn below.
There is no method for removing constraints. Therefore if you have a constraint that you
                  wish to sometimes be in force and other times not be in force, you should use <state>
                   s.
            
The syntax for coding a constraint is:
$when{expression}
where:
$ is the token indicating a constraint.
                        
                                      is an optional compiler directive, and is one of:
                        when
                                    
immediately: evaluated at load time; it is the default, but should only be
                                        used for constant expressions.
                                        $immediately{expression} is the same as 
                                            expression
                                           .
                              once: evaluated at initialization time; it can refer to other
                                        nodes that precede this one. 
                                 | ![[Note]](images/note.png) | Note | 
|---|---|
| A  | 
always: will track changes in the values referred to.
                                          $always{expression} can be abbreviated to
                                          ${expression}. 
                                 | ![[Note]](images/note.png) | Note | 
|---|---|
| An  | 
{ and } are tokens delimiting the expression to be
                                 evaluated
                        
                                      is a JavaScript expression
                        expression
                                    
The following example shows the use of constraints in tags:
Example 27.1. Constraints in tags
<canvas height="160" width="100%">
    <simplelayout spacing="5"/>
    <slider id="m" value="25" minvalue="0" maxvalue="100"/>
    <text text="$immediately{'immediately: ' + (m?m.value:'undefined')}"/>
    <text text="$once{'once: ' + (m?m.value:'undefined')}"/>
    <text text="$always{'always: ' + (m?m.value:'undefined')}"/>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                     Here's what the different values for when do:
               
immediately: undefined, because the slider does not exist until the program
                             runs. If you run this example with the debugger on, you will see a warning.
                     once: set to the slider value when the program loads.
                     always: track changes in the slider value.
                     The following example uses the applyConstraintMethod() method inherited from lz.node in order to create a constraint at runtime. You'll
                      see that the setAttribute() method has the same effect as the simple
                      expression y=${m.y}
                     
               
Example 27.2. Runtime constraints with applyConstraintMethod
<canvas width="100%"> 
  <view x="250" width="20" height="20" bgcolor="red" y="${m.y}"/> 
  <view x="300" width="20" height="20" bgcolor="blue"> 
    <handler name="oninit"> 
      var d = [m, "y"]; 
      this.applyConstraintMethod("myConstraintMethod", d); 
    </handler> 
    <method name="myConstraintMethod" args="ignore"> 
      this.setAttribute("y", m.y); 
    </method> 
  </view> 
  <window id="m" x="10" title="Drag me" width="160" height="20"/> 
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                     myConstraintMethod is a callback function that is required for the applyConstraintMethod() method. d is an
                      array consisting of a pointer to a reference node, and the attribute to bind to.
               
OpenLaszlo applications can use something called a delegate in script to associate a method or any global function with an event. When the event is triggered, the method is called.
The above constraint expression could also be written in script as:
    <handler name="oninit">
      var y_del = new LzDelegate(this, "myConstraintMethod");
      y_del.register(m, "ony");
    </handler> 
    <method name="myConstraintMethod" args="newValue">
      this.setAttribute("y", m.y); 
    </method>
You can read more about delegates in Chapter 30, Delegates.
States are a convenient way to set and remove constraints at runtime.
You create states using the <state>
                       tag, for example:
               
Example 27.3. states and constraints
<state name="flexistate">
    <attribute name="width" value="${parent.width}" />
</state>
<state name="boringstate" apply="false">
    <attribute name="width" value="50" />
</state>
States are further explained in Chapter 32, States .
Whenever the value of an attribute changes, its on event is generated. Because a constraint is an attribute whose
                  value is dependent upon the values of one or more other attribute(s), the value of the constraint
                  is recalculated whenever it receives the on event for the attributes on which it depends. 
            
Consider
 
<view name="someView" 
   width="${someAttribute + someOtherAttribute}" 
   /> 
Then the value of someView.width would be recomputed whenever an onsomeAttribute or onsomeOtherAttribute event occurred.
            
So for example
<view name="beatles" width="${this.paul.width + 28}">
   <view name="paul" onclick="clickhandler()">
      <!-- clickhandler method here to increase paul's width based on user clicking mouse -->
   </view>
</view>
The width of beatles will increase or decrease as a function of
                   paul's width; the expression this.paul.width + 28 is a
                  constraint.
            
This is a trivial example, but it serves to make the point that in declaring the structure of your objects in LZX you also declare the rules by which they will relate to each other. Constraints are a fundamental concept in LZX programming, and learning to "think in LZX" is a mostly a matter of learning to properly model your system's behavior in terms of the constraints on its constituent parts.
You can think about constraints as modeling real system interrelationships. A constraint expression can establish that two objects are connected.
In the example below, the visibility of the blue square is connected to the value of the checkbox. When you toggle the checkbox, the visibility of the blue square automatically switches as well.
Example 27.4. An element appears when a checkbox is set
<canvas height="120" width="100%">
  <checkbox id="cb" text="Show Blue Square"/>
  <view visible="${cb.value}" width="30" height="30" bgcolor="blue"/>
  <simplelayout/>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                     In the example below, the position of the blue square is connected to the position of the mouse. If you move the mouse inside the canvas, the blue square will move as the mouse moves, floating relative to the position of the mouse. In this case, the constraint expression includes a method call, but it works in the same way as the simple attribute expression in the previous example.
Example 27.5. Constrain to mouse position
<canvas height="120" width="100%">
  <view bgcolor="blue" width="40" height="40" x="${parent.getMouse('x')}" y="${parent.getMouse('y')}"/>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                     The constraint expression may be almost any Javascript expression. For example, you could
                      change the y value in the previous example to
                      y="${immediateparent.getMouse('y')+10}" and cause the blue square to float
                      below the mouse. If you centered the blue square at the mouse position by setting the y value
                      with y="${immediateparent.getMouse('y') - this.width/2}" — if the width of
                      the blue square changes, the y value with be updated to position the blue square relative to the
                      new width and the mouse position.
               
See Constraints and Functions, below, for limitations on the types of expression you can use in constraints.
Every constraint has one or more dependencies. For example, the constraint expression:
width="${parent.width}"
creates a dependency on the parent's width attribute. As explained in Chapter 29, Methods, Events, Handlers, and Attributes, whenever an attribute is set by calling
                   setAttribute('whatever', 4)  an onwhatever event is sent. Following the above example for the width attribute, an onwidth event is sent whether the attribute has been set with
                   setAttribute, setWidth() or by another constraint.
            
When you use a constraint expression, a function is automatically generated to set the value of the attribute. That function is then called whenever an event is triggered on which the constraint has a dependency.
Constraints can have dependencies on multiple attributes. In the code below, the width attribute is dependent on the
                  immediateparent's width attribute and the parent's
                  bordersize attribute. When either attribute is set the width updates. Immediateparent.width is used
                  instead of parent.width, because immediateparent, in this case, is the interior view of the
                  window, while parent is the whole window.
            
width="${immediateparent.width - parent.bordersize * 2}"
Experiment with the working example below to see multiple dependencies in action. Resizing the window will resize the blue bar. You can also move the slider to adjust the border size.
Example 27.6. Multiple Dependencies
<canvas height="300" width="100%">
  <window width="400" height="200" resizable="true">
    <attribute name="bordersize" value="${editor.bordersize.value}"/>
    <view y="20" name="editor" layout="axis:x; spacing:10; inset:10">
      <text y="-4" resize="true">bordersize:</text>
      <slider name="bordersize" value="10"/>
    </view>
    <view bgcolor="0xFFC834" y="80" width="${immediateparent.width}" height="10"/>
    <view x="${parent.bordersize}" y="80" width="${immediateparent.width - parent.bordersize * 2}" height="10" bgcolor="blue"/>
    
  </window>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                  A constraint loop exists when the value of an attribute A depends on
                   B, and B depends on A. It's actually a
                  very natural thing to do in LZX. For example, in the Laszlo application below, the
                  y values of the red and blue squares are constrained to each other. 
            
Example 27.7. Circular constraints
<canvas height="120" width="100%">
  <include href="lz/slider.lzx"/>
  <view name="redview" bgcolor="red" width="40" height="40" x="${blueview.x - 300}">
  </view>
  <view name="blueview" bgcolor="blue" width="40" height="40" x="${redview.x + 300}">
  </view>
  <slider x="10" y="50" value="50" onvalue="redview.setAttribute('x', this.value)" showvalue="false" showrange="false"/>
  <slider x="310" y="50" value="50" onvalue="blueview.setAttribute('x', this.value + 300)" showvalue="false" showrange="false"/>
</canvas>
<!-- * X_LZ_COPYRIGHT_BEGIN ***************************************************
* Copyright 2007, 2008 Laszlo Systems, Inc.  All Rights Reserved.                   *
* Use is subject to license terms.                                            *
* X_LZ_COPYRIGHT_END ****************************************************** -->
                   How does it work? When you drag the red view to change its own y position, it sends an ony event. The blue view is listening for the red view's ony event and responds by updating its own y position. The red
                  view is listening for the blue view's ony event; however, it doesn't respond to that event because an
                  event handler only gets called one time on each event.
            
Constraints are an effective way to write user interface code and in some cases to manage non-visual application state. As with any code, you will want to understand the performance implications, as well as when it is best to use constraints as opposed to alternate methods of achieving similar effects.
 Often you will want to use constraint expressions to create the initial state of your
                      application, but you don't need attributes to update dynamically while the application is in
                      use. In this case, you can improve startup time performance by declaring when
                      the expression should be evaluated. 
               
When you write a constraint using the ${...} syntax (as in the example
                      below), when="always" is the default.
               
<view width="${parent.width}" height="10" bgcolor="yellow"/>
To optimize this expression for the case when the dependency will not change, you will want
                      to specify when="once":
               
<view width="$once{parent.width}" height="10" bgcolor="yellow"/>
When declaring class attributes, the attribute is typically declared using an <attribute>
                       tag, where the when value may be declared
                      explicitly:
               
<class name="myclass">
  <attribute name="width" value="${parent.width}" when="once"/>
</class>
 In this case if 
                           is not specified, the value is when
                         immediately, which means that it
                      initializes the attribute to the value of the expression when the enclosing element is defined.
                      The value must be a constant expression and cannot depend on any other objects.
               
 Constraints can be very useful for positioning and determining the size of views. However,
                      if you have a large number of views updating based on the same information, it is better to use
                      a <layout>
                       instead of writing a complex constraint system. There are quite a few
                      layouts available in the OpenLaszlo platform, and furthermore you can write your own if none of
                      these meet your needs. See Chapter 17, Layout and Design for more on this subject. 
               
Generally, if you have a lot of different things that need to be updated based on a single dependency, it is optimal to write a setter for the dependent attribute and in that setter take appropriate actions. See Chapter 29, Methods, Events, Handlers, and Attributes for more on this subject.
Take care when using JavaScript functions inside of constraints.
In general, there are only a limited number of LZX functions that have dependency functions and can be expected to correctly participate in a constraint. No ECMAScript functions have dependency functions, so none of them will work properly in a constraint.
 More precisely, ECMAScript functions will work properly if they are stateless (they depend
                  only on the values of their arguments), so, for example,  value="Math.max(parent.width,
                      parent.height)" will do the right thing. (Any stateless function works.) However, many
                  apparently simple functions do not work within constrains. 
            
Consider
     <param value="${escape(canvas.options.serialize())}"/>
in which the value of a parameter is constrained to that returned by a serializing function. Upon inspection, we see that the dependencies of
     value="${escape(canvas.options.serialize())}"
will be calculated as:
the dependencies of escape() (which includes the value of
                              canvas.options.serialize())
                     
the dependencies of serialize()
In this case, value gets evaluated too early (i.e. before the dataset has
                  any data) and that's why you don't see any data. Instead, you would use getValue() which acts as a getter for <param>, instead of using a constraint.
            
 In evaluating dependencies in constraints, the OpenLaszlo compiler only looks at the 'tail'
                  of a chain, so if you have an expression a.b.c, only c will be depended on. For a function, the
                  function itself computes its dependencies, based on its arguments. In the case of
                  escape, it doesn't have a dependency function, nor does
                  serialize, so in this particular example, there will be no dependencies at
                  all. 
            
 EXCEPT that the constraint mechanism only looks at a tail, so for example NEITHER
                   value="parent.selected.width" NOR value="Math.max(parent.width,
                      parent.selected.width" will work if parent.selected changes value
                  (it's fine if parent.selected stays the same but
                   parent.selected.width changes). 
            
The bottom line is that the constraint calculator is not really designed to be used in functions. It works for many situations, but not for anything complex.
Copyright © 2002-2010 Laszlo Systems, Inc. All Rights Reserved. Unauthorized use, duplication or distribution is strictly prohibited. This is the proprietary information of Laszlo Systems, Inc. Use is subject to license terms.