Validation

8 views
Skip to first unread message

Bruno

unread,
Oct 5, 2011, 11:34:14 AM10/5/11
to bindage-tools
Hello again,

Today I started testing some features of the framework, and I have
some doubts about it...

Let me start by saying I'm using Flash Builder 4.5.1

I'm trying to validate my logon screen with login and password fields
using swiz, on my presentation model I've binded the property
errorString of the fields, but after initialization nothing seems to
happen, maybe I'm missing something but I just wanted to make my field
turn red like flex's default validator would do.

any advice?

Matthew Hall

unread,
Oct 5, 2011, 11:36:35 AM10/5/11
to bindag...@googlegroups.com

Did you configure your Swiz with the custom metadata processor? Are you annotating your binding setup method with [DataBinding]?

Matthew

Bruno Tourinho

unread,
Oct 5, 2011, 12:30:00 PM10/5/11
to bindag...@googlegroups.com
Yup, everything is set as described on the example...

Matthew Hall

unread,
Oct 5, 2011, 12:31:56 PM10/5/11
to bindag...@googlegroups.com

Can you provide a snippet of your code?

Matthew

Bruno Tourinho

unread,
Oct 5, 2011, 12:55:39 PM10/5/11
to bindag...@googlegroups.com
Sure... goes like this... the variable names may be in portuguese (I'm from Brazil)

VIEW

<s:Form skinClass="spark.skins.spark.StackedFormSkin">
        <s:FormItem label="Login" required="true">
            <s:TextInput id="txtLogin" errorString="{pmLogin.loginErrorString}"/>
        </s:FormItem>
        <s:FormItem label="Senha" required="true">
            <s:TextInput id="txtSenha" errorString="{pmLogin.senhaErrorString}"/>                         
        </s:FormItem>
</s:Form/>
<s:Button id="btnEntrar" label="Entrar" enabled="{pmLogin.enterEnabled}" click="btnEntrar_clickHandler(event)"/>

PRESENTATION MODEL

[Dispatcher]
        public var dispatcher:IEventDispatcher;
       
        [Bindable]
        public var login:String
        [Bindable]
        public var loginErrorString:String
       
        [Bindable]
        public var senha:String
        [Bindable]
        public var senhaErrorString:String
       
        [Bindable]
        public var enterEnabled:Boolean;

        [DataBinding]
        public function initBindings():void
        {           
            Bind.fromProperty(this, "login").convert(validateLogin).toProperty(this, "loginErrorString");
            Bind.fromProperty(this, "senha").convert(validateSenha).toProperty(this, "senhaErrorString");

            Bind.fromProperty(this, "login").convert(validateRequiredString).toProperty(this, "loginErrorString");
            Bind.fromProperty(this, "senha").convert(validateRequiredString).toProperty(this, "senhaErrorString");
           
            Bind.fromAll(Bind.fromProperty(this, "loginErrorString"),Bind.fromProperty(this, "senhaErrorString")).convert( toCondition(everyItem(equalTo(null))) ).toProperty(this, "enterEnabled");

        }

        private function validateRequiredString(value:String):String
        {
            if (value == null || value.length == 0)
            {
                return "Campo obrigatório";
            }
            return null;
        }
               
        private static function validateLogin(login:String):String
        {           
            return login && login.length > 0 ? null : "Digite o login";       
        }
       
        private static function validateSenha(senha:String):String
        {           
            return senha && senha.length > 0 ? null : "Digite a senha";           
        }

"long coding short", that is it... I'm also sending you the project in FXP so you can take a look...

Thanks for the help
LearningBindage.fxp

Matthew Hall

unread,
Oct 5, 2011, 1:09:05 PM10/5/11
to bindag...@googlegroups.com
Looks like you missed binding your presentation model fields to your UI controls. Try adding this to your login view:

[DataBinding]
public function initBindings():void {
  Bind.twoWay(
      Bind.fromProperty(pmLogin, 'login'),
      Bind.fromProperty(txtLogin, 'text'));

  Bind.twoWay(
      Bind.fromProperty(pmLogin, 'senha'),
      Bind.fromProperty(txtSenha, 'text'));
}


Matthew

Matthew Hall

unread,
Oct 5, 2011, 1:10:02 PM10/5/11
to bindag...@googlegroups.com
Nice click handler in the login view, btw ;)

Matthew Hall

unread,
Oct 5, 2011, 1:14:26 PM10/5/11
to bindag...@googlegroups.com
Also, since you're using Flex 4, you could trying using a two-way binding e.x. text="@{pmLogin.login}" and avoid needing BindageTools in your views.

Bruno Tourinho

unread,
Oct 5, 2011, 1:53:48 PM10/5/11
to bindag...@googlegroups.com
LOL you can't imagine the messy names I use in my development environment... sorry for that... ;)

I thought that the [databinding] tag would be only on PM!

I'll try the way you said and I'll let you know...

Thanks again...

Bruno

Bruno Tourinho

unread,
Oct 5, 2011, 2:18:46 PM10/5/11
to bindag...@googlegroups.com
Hey Matthew,
Looks like I'm not in one of my best days...

Made the changes you said, but while debugging

an error was thrown at this line:
Bind.fromAll(
                Bind.fromProperty(this, "loginErrorString"),
                Bind.fromProperty(this, "senhaErrorString"))
                .convert( toCondition(everyItem(equalTo(null))) ).toProperty(this, "enterEnabled");

It seems to be something with toCondition parameters...

ArgumentError: Expected 1 arguments, received 2
    at Function/<anonymous>()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/converters/toCondition.as:86]
    at Function/http://adobe.com/AS3/2006/builtin::apply()
    at com.googlecode.bindagetools.impl::ConvertPipeline/run()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/ConvertPipeline.as:31]
    at Function/com.googlecode.bindagetools.impl:MultiPipelineBuilder/protected:pipelineRunner/com.googlecode.bindagetools.impl:pipelineRunner()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/MultiPipelineBuilder.as:44]
    at com.googlecode.bindagetools.impl::SetArgAndContinuePipeline/run()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/SetArgAndContinuePipeline.as:42]
    at Function/<anonymous>()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/PropertyPipelineBuilder.as:64]
    at com.googlecode.bindagetools.impl::SetArgAndContinuePipeline/run()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/SetArgAndContinuePipeline.as:42]
    at Function/<anonymous>()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/PropertyPipelineBuilder.as:64]
    at Function/http://adobe.com/AS3/2006/builtin::apply()
    at Function/<anonymous>()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/util/preventRecursion.as:32]
    at Function/com.googlecode.bindagetools.impl:PipelineBuilder/private:toPipeline/com.googlecode.bindagetools.impl:handler()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/PipelineBuilder.as:163]
    at com.googlecode.bindagetools.impl::PipelineBuilder/toPipeline()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/PipelineBuilder.as:168]
    at com.googlecode.bindagetools.impl::PipelineBuilder/toProperty()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/impl/PipelineBuilder.as:95]
    at br.com.test.presentation::LoginPM/initBindings()[C:\PROJECTS\Flex45\LearningBindage\src\br\com\test\presentation\LoginPM.as:47]
    at Function/http://adobe.com/AS3/2006/builtin::apply()
    at com.googlecode.bindagetools::BindTracker$/collect()[/home/mahall/dev/BindageTools/bindage-tools/src/main/flex/com/googlecode/bindagetools/BindTracker.as:56]
    at com.googlecode.bindagetools.swiz::DataBindingProcessor/setUpBindings()[/home/mahall/dev/BindageTools/bindage-tools-swiz/src/main/flex/com/googlecode/bindagetools/swiz/DataBindingProcessor.as:120]
    at com.googlecode.bindagetools.swiz::DataBindingProcessor/setUpMetadataTag()[/home/mahall/dev/BindageTools/bindage-tools-swiz/src/main/flex/com/googlecode/bindagetools/swiz/DataBindingProcessor.as:112]
    at org.swizframework.processors::BaseMetadataProcessor/setUpMetadataTags()[/Users/Chris/Documents/my_projects/swizframework-git/swiz-framework/src/org/swizframework/processors/BaseMetadataProcessor.as:118]
    at org.swizframework.core::BeanFactory/setUpBean()[/Users/Chris/Documents/my_projects/swizframework-git/swiz-framework/src/org/swizframework/core/BeanFactory.as:367]
    at org.swizframework.core::BeanFactory/completeBeanFactorySetup()[/Users/Chris/Documents/my_projects/swizframework-git/swiz-framework/src/org/swizframework/core/BeanFactory.as:128]
    at org.swizframework.core::BeanFactory/setUp()[/Users/Chris/Documents/my_projects/swizframework-git/swiz-framework/src/org/swizframework/core/BeanFactory.as:114]
    at org.swizframework.core::Swiz/init()[/Users/Chris/Documents/my_projects/swizframework-git/swiz-framework/src/org/swizframework/core/Swiz.as:373]
    at org.swizframework.core.mxml::Swiz/handleContainerPreinitialize()[/Users/Chris/Documents/my_projects/swizframework-git/swiz-framework/src/org/swizframework/core/mxml/Swiz.as:78]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at mx.core::UIComponent/dispatchEvent()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\core\UIComponent.as:13128]
    at mx.core::UIComponent/initialize()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\core\UIComponent.as:7614]
    at spark.components::Application/initialize()[E:\dev\4.5.1\frameworks\projects\spark\src\spark\components\Application.as:1334]
    at LearningBindage/initialize()
    at mx.managers.systemClasses::ChildManager/childAdded()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\managers\systemClasses\ChildManager.as:189]
    at mx.managers.systemClasses::ChildManager/initializeTopLevelWindow()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\managers\systemClasses\ChildManager.as:359]
    at mx.managers::SystemManager/initializeTopLevelWindow()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\managers\SystemManager.as:3063]
    at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::kickOff()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\managers\SystemManager.as:2849]
    at mx.managers::SystemManager/http://www.adobe.com/2006/flex/mx/internal::preloader_completeHandler()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\managers\SystemManager.as:2729]
    at flash.events::EventDispatcher/dispatchEventFunction()
    at flash.events::EventDispatcher/dispatchEvent()
    at mx.preloaders::Preloader/timerHandler()[E:\dev\4.5.1\frameworks\projects\framework\src\mx\preloaders\Preloader.as:542]
    at flash.utils::Timer/_timerDispatch()
    at flash.utils::Timer/tick()

Matthew Hall

unread,
Oct 5, 2011, 2:33:56 PM10/5/11
to bindag...@googlegroups.com

Try .convert(args(), everyItem(equalTo(null)))

Bruno Tourinho

unread,
Oct 5, 2011, 2:47:17 PM10/5/11
to bindag...@googlegroups.com
1137: Incorrect number of arguments. Expected no more than 1.

there is something with convert function... is it possible to be something with my hamcrest version?
I'm using hamcrest-as3-flex-1.1.3.swc

Bruno Tourinho

unread,
Oct 5, 2011, 3:05:10 PM10/5/11
to bindag...@googlegroups.com
I've tried something like:


Bind.fromAll(
                Bind.fromProperty(this, "loginErrorString"),
                Bind.fromProperty(this, "senhaErrorString"))
                .convert(function():Matcher{return everyItem(equalTo(null))}).toProperty(this, "enterEnabled");

No success..

Matthew Hall

unread,
Oct 5, 2011, 3:50:01 PM10/5/11
to bindag...@googlegroups.com

To use a matcher with multiple values in the pipeline, you have to use a function to convert varargs into an array:

.convert(args(), everyItem(nullValue()))

Matthew

Matthew Hall

unread,
Oct 5, 2011, 3:51:24 PM10/5/11
to bindag...@googlegroups.com

Oops, that should have been:

.convert( toCondition(args(), everyItem(nullValue())) )

Matthew

Matthew Hall

unread,
Oct 5, 2011, 4:35:53 PM10/5/11
to bindag...@googlegroups.com

By default, when you have multiple binding sources, each source becomes a separate argument to converter and validator functions.

However Hamcrest matchers have only a single method argument. So in order to match multiple values you have to convert them into a single object. The args() function is a converter which returns its arguments as an array.

We do this so you have flexibility on what aspect of the argument(s) you want to match against.

As an example, assume you have 3 parties that want to divide up a check. The contribution percentages must add up to 100% of the check amount:


function sum(...values):Number {

  var result:Number = 0;

  for (var value:Number in values) {

    result += value;

  }

  return result;

}


Bind.fromAll(

    Bind.from(john, 'percentContribution'),

    Bind.from(mary, 'percentContribution'),

    Bind.from(tim, 'percentContribution')

    )

    .convert( toCondition(sum, greaterThanOrEqualTo(100)) )

    .toProperty(this, 'contributionPercentagesValid');


The toCondition and IPipelineBuilder.validate methods accept several different variants of arguments. Take a look at the asdoc comments in the sources.

Hope this helps,

Matthew

Matthew Hall

unread,
Oct 5, 2011, 4:49:46 PM10/5/11
to bindage-tools
On Oct 5, 11:53 am, Bruno Tourinho <bruno...@gmail.com> wrote:
> I thought that the [databinding] tag would be only on PM!

In Flex 4, you'd be right--use BindageTools in PMs, and declarative
bindings in views to wire up the PM to the view.

In Flex 3 however, two-way bindings are not as easy to set up since
you don't have the @{foo.bar} syntax. So you end up using either
<mx:Binding twoWay="true"> tags, or [DataBinding] methods to set them
up. I usually prefer BindageTools since it's a little more tolerant of
values initially being null than declarative bindings are.

Matthew

Matthew Hall

unread,
Oct 7, 2011, 6:35:41 PM10/7/11
to bindage-tools
Brune, I've pushed a changeset which improves the exception messages
in toCondition and IPipelineBuilder.validate to remind clients to
either use an attribute function to coalesce multiple pipeline values,
or to provide an equal number of matchers as there are pipeline
values.

Would you try it out and tell me if the message is more helpful?

Matthew

Bruno Tourinho

unread,
Oct 7, 2011, 6:38:59 PM10/7/11
to bindag...@googlegroups.com
Sure Matt, I had to stop studying this week, because of some projects deadlines... but i'll test it this weekend and let you know...

Bruno Tourinho

unread,
Oct 10, 2011, 2:07:37 AM10/10/11
to bindag...@googlegroups.com
Hey Matt, good news...I figured out how to make it work using: .convert( toCondition(args(), everyItem(nullValue())) )

But I must be doing something wrong still, even after filling the field my errorMessage shows "null" as message... o.O (project attached)

another question, when we set the validation, the field starts as invalid, is there a way to start field as valid and invalidate it after focus change for instance? it might sound dumb, i know...

regards
LearningBindage.fxp

Matthew Hall

unread,
Oct 10, 2011, 2:24:47 PM10/10/11
to bindag...@googlegroups.com
I'm not sure, but your errorString="{pmLogin.loginErrorString}" declarative binding might be turning the null value to the "null" string. You could try {pmLogin.loginErrorString || ''} instead (that's two single quotes, not a double-quote).

You might also try using a BindageTools binding inside your initBindings method instead of declarative bindings and see if that gives a different result.

Another issue I spotted in LoginView.mxml:

[PostConstruct]

[DataBinding]
public function initBindings():void {
...
}

You do not want both [PostConstruct] and [DataBinding] on a single method--this will cause it to be invoked twice on startup.

[DataBinding] is similar to [PostConstruct], except that [DataBinding] makes sure that the bindings you create inside that method will be disposed when the view is disposed later.

Matthew

Bruno Tourinho

unread,
Oct 10, 2011, 7:44:02 PM10/10/11
to bindag...@googlegroups.com
Hello again Matt, It worked like a charm :)
The only issue now is to initialize the fields as valid (without errorString)
Thanks a lot...

Matthew Hall

unread,
Oct 10, 2011, 8:38:44 PM10/10/11
to bindag...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages