Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

  • Isomorphic
    replied
    Thanks for the clear test case - very helpful.
    We've made a change which should address this issue. It will be present in the next nightly build (Jan 26) - please give it a try and let us know if you continue to see issues!

    Regards
    Isomorphic Software

    Leave a comment:


  • tmoes
    replied
    Hi Isomorphic,

    here my test case, i extended your example builtinds.
    please change employees.ds.xml and this EntryPoint class.

    I changed your method bindComponents and insert "class myValidator".

    Code:
    package com.smartgwt.sample.client;
    
    import com.google.gwt.core.client.EntryPoint;
    import com.smartgwt.client.core.KeyIdentifier;
    import com.smartgwt.client.data.DataSource;
    import com.smartgwt.client.data.Record;
    import com.smartgwt.client.types.SelectionStyle;
    import com.smartgwt.client.types.SortArrow;
    import com.smartgwt.client.util.KeyCallback;
    import com.smartgwt.client.util.Page;
    import com.smartgwt.client.util.SC;
    import com.smartgwt.client.widgets.IButton;
    import com.smartgwt.client.widgets.Label;
    import com.smartgwt.client.widgets.events.ClickEvent;
    import com.smartgwt.client.widgets.events.ClickHandler;
    import com.smartgwt.client.widgets.form.DynamicForm;
    import com.smartgwt.client.widgets.form.validator.CustomValidator;
    import com.smartgwt.client.widgets.form.validator.Validator;
    import com.smartgwt.client.widgets.grid.ListGrid;
    import com.smartgwt.client.widgets.grid.ListGridField;
    import com.smartgwt.client.widgets.grid.ListGridRecord;
    import com.smartgwt.client.widgets.grid.events.RecordClickEvent;
    import com.smartgwt.client.widgets.grid.events.RecordClickHandler;
    import com.smartgwt.client.widgets.layout.HLayout;
    import com.smartgwt.client.widgets.layout.VStack;
    import com.smartgwt.client.widgets.viewer.DetailViewer;
    
    /**
     * Entry point classes define <code>onModuleLoad()</code>.
     */
    public class BuiltInDS implements EntryPoint {
        private ListGrid boundList;
        private DynamicForm boundForm;
        private IButton saveBtn;
        private DetailViewer boundViewer;
        private IButton newBtn;
    
        
       
        /**
         * This is the entry point method.
         */
        public void onModuleLoad() {
    		Validator.addValidatorDefinition("ValidatorPacs008", new myValidator());
    
            KeyIdentifier debugKey = new KeyIdentifier();
            debugKey.setCtrlKey(true);
            debugKey.setKeyName("D");
    
            Page.registerKey(debugKey, new KeyCallback() {
                public void execute(String keyName) {
                    SC.showConsole();
                }
            });
    
      
            
            ListGrid grid = new ListGrid();
            grid.setLeft(20);
            grid.setTop(75);
            grid.setWidth(130);
            grid.setLeaveScrollbarGap(false);
            grid.setShowSortArrow(SortArrow.NONE);
            grid.setCanSort(false);
            grid.setFields(new ListGridField("dsTitle", "Select a DataSource"));
            grid.setData(new ListGridRecord[]{
                    new DSRecord("Animals", "animals"),
                    new DSRecord("Office Supplies", "supplyItem"),
                    new DSRecord("Employees", "employees")}
            );
            grid.setSelectionType(SelectionStyle.SINGLE);
            grid.addRecordClickHandler(new RecordClickHandler() {
                public void onRecordClick(RecordClickEvent event) {
                    DSRecord record = (DSRecord) event.getRecord();
                    bindComponents(record.getDsName());
                }
            });
    
            grid.draw();
    
            VStack vStack = new VStack();
            vStack.setLeft(175);
            vStack.setTop(75);
            vStack.setWidth("70%");
            vStack.setMembersMargin(20);
    
            Label label = new Label();
            label.setContents("<ul>" +
                    "<li>select a datasource from the list at left to bind to these components</li>" +
                    "<li>click a record in the grid to view and edit that record in the form</li>" +
                    "<li>click <b>New</b> to start editing a new record in the form</li>" +
                    "<li>click <b>Save</b> to save changes to a new or edited record in the form</li>" +
                    "<li>click <b>Clear</b> to clear all fields in the form</li>" +
                    "<li>click <b>Filter</b> to filter (substring match) the grid based on form values</li>" +
                    "<li>click <b>Fetch</b> to fetch records (exact match) for the grid based on form values</li>" +
                    "<li>double-click a record in the grid to edit inline (press Return, or arrow/tab to another record, to save)</li>" +
                    "</ul>");
            vStack.addMember(label);
    
            boundList = new ListGrid();
            boundList.setHeight(200);
            boundList.setCanEdit(true);
    
            boundList.addRecordClickHandler(new RecordClickHandler() {
                public void onRecordClick(RecordClickEvent event) {
                    Record record = event.getRecord();
                    boundForm.editRecord(record);
                    saveBtn.enable();
                    boundViewer.viewSelectedData(boundList);
                }
            });
            vStack.addMember(boundList);
    
            boundForm = new DynamicForm();
            boundForm.setNumCols(6);
            boundForm.setAutoFocus(false);
            vStack.addMember(boundForm);
    
            HLayout hLayout = new HLayout(10);
            hLayout.setMembersMargin(10);
            hLayout.setHeight(22);
    
            saveBtn = new IButton("Save");
            saveBtn.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent event) {
                    boundForm.saveData();
                    if (!boundForm.hasErrors()) {
                        boundForm.clearValues();
                        saveBtn.disable();
                    }
                }
            });
            hLayout.addMember(saveBtn);
    
            newBtn = new IButton("New");
            newBtn.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent event) {
                    boundForm.editNewRecord();
                    saveBtn.enable();
                }
            });
            hLayout.addMember(newBtn);
    
            IButton clearBtn = new IButton("Clear");
            clearBtn.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent event) {
                    boundForm.clearValues();
                    saveBtn.disable();
                }
            });
            hLayout.addMember(clearBtn);
    
            IButton filterBtn = new IButton("Filter");
            filterBtn.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent event) {
                    boundList.filterData(boundForm.getValuesAsCriteria());
                    saveBtn.disable();
                }
            });
            hLayout.addMember(filterBtn);
    
            IButton fetchBtn = new IButton("Fetch");
            fetchBtn.addClickHandler(new ClickHandler() {
                public void onClick(ClickEvent event) {
                    boundList.fetchData(boundForm.getValuesAsCriteria());
                    saveBtn.disable();
                }
            });
            hLayout.addMember(fetchBtn);
    
            vStack.addMember(hLayout);
    
            boundViewer = new DetailViewer();
            vStack.addMember(boundViewer);
    
            vStack.draw();
           
        }
    
        private void bindComponents(String dsName) {
            DataSource ds = DataSource.get(dsName);
            
            boundList.setDataSource(ds);
            boundList.setUseAllDataSourceFields(true);
            
            boundForm.setDataSource(ds);
         
    
        	
            if (dsName.equalsIgnoreCase("employees")){
            	
    //set the CustomValidator manually at Filed Email
    
        		ListGridField listGridField = new ListGridField("Email");
        		listGridField.setValidators(new myValidator());
        		boundList.setFields(listGridField);
        	
        		boundForm.getField("Email").setValidators(new myValidator());
            }
        	
            boundForm.setUseAllDataSourceFields(true);   
            
            
            
            //boundViewer.setDataSource(ds);
    
            boundList.fetchData();
            newBtn.enable();
            saveBtn.disable();
        }
    }
    
    class myValidator extends CustomValidator{
    
    	@Override
    	protected boolean condition(Object value) {
    
    		System.out.println(value.toString());
    		if (value.toString().startsWith("US")){
    			setErrorMessage("only europe countrys allowed");
    		}else{
    			if (value.toString().startsWith("DE")){
    				setErrorMessage("germany is not valid");
    			}else{
    				if (value.toString().startsWith("123")){
    					setErrorMessage("are you sure?");
    				}else
    					return true;
    			}
    		}
    		
    		return false;
    	}
    	
    }

    Please choose datasource employees and type "DEtest" or "UStest" in field Title and Email, now you will see the different result. (look at screenshot's)

    Since it is the same validator, I expect the same error messages.

    Is it understandable?

    regards,
    timo
    Attached Files

    Leave a comment:


  • Isomorphic
    replied
    You need to specify myProperty in the .ds.xml file. This handles your use case as you've explained it. If that's not your use case, start over, and show a test case for how you're trying to set the errorMessage dynamically.

    Leave a comment:


  • tmoes
    replied
    sorry....

    my ds.xml
    Code:
     
    <field hidden="false" required="false" detail="true" title="Instructing Agent" name="instgagtfininstnidbic" length="11" type="text">
    	<validators>
    		<validator type="ValidatorPacs008"
    			errorMessage="must be ${validator.myProperty} before end !">
    		</validator>
    	</validators>
    </field>
    In my validator class, I tried the following, but all without success.
    Class: ValidatorPacs008.java

    setErrorMessage("my dynamic custom errormessage");
    or/and
    setAttribute("myProperty", "my dynamic custom errormessage");

    On the screenshot you can see that it is not generated dynamically.

    If this validator I assigns to each field (setValidators) individually it works, yes.
    Attached Files

    Leave a comment:


  • Isomorphic
    replied
    The errorMessage is also dynamically evaluated client-side. Notice some of the built-in messages like "Must be exactly ${max} characters". You can do the same (eg "Must be less than ${validator.myProperty}" for a custom property "myProperty" that you placed on the field in .ds.xml.

    Leave a comment:


  • tmoes
    replied
    but the errormessage declared in ds.xml it's static and not dynamic, depending on the result.
    You do not understand what I mean?

    Leave a comment:


  • Isomorphic
    replied
    In a client-side validator declared in the .ds.xml file you just set the errorMessage attribute (as in errorMessage="Must be before 2020").

    If you think there's an issue here, please show a test case that we can run to see the issue.

    Leave a comment:


  • tmoes
    replied
    i know this example. but I need in this case, no server validator (client only). This is slightly overdone.

    I have written many custom validators (extends com.smartgwt.client.widgets.form.validator.CustomValidator) and they added with "setValidators" by any field. In this case also works setErrorMessage.

    Now I would like to define the validators in the ...ds.xml unfortunately setErrorMessages remains without effect.

    Can you please check whether it is a bug?

    thanks,
    timo

    Leave a comment:


  • Isomorphic
    replied
    Hi tmoes,

    See this sample for how a DMI validator can make variables available to the error message (which can be a Velocity expression).

    Leave a comment:


  • tmoes
    replied
    hi,

    how can I set the errorMessage dynamic?

    Example:
    if date1 < date2:
    message="Date1 less than Date2"

    if date1 > date2:
    message="Date1 greater than Date2"

    The method setErrorMessage(message) in the class IsBeforeValidator (example) does not work. In this case, I always get "invalid Value" message.

    Is it possible to set the error message dynamically, I need it in a listGrid with (Listgrid.setUseAllDataSourceFields)?

    Code:
    <field .....>
    	<validators>
    		<validator type="IsBeforeValidator"></validator>
    	</validators>
    </field>
    Thanks,
    Timo
    Last edited by tmoes; 20 Jan 2011, 10:12.

    Leave a comment:


  • bade
    replied
    Thanks for the heads up, Nikolay... but I think I'll wait for the fix.
    I still have a lot of other stuff to do anyways ;-)

    Leave a comment:


  • nikolayo
    replied
    Thank you for the prompt fix!

    Regards
    Nikolay

    Leave a comment:


  • smartgwt.dev
    replied
    The latest build has a method on CustomValidator :

    public Map getValidatorProperties() that provides access to any user defined validator properties.

    Leave a comment:


  • nikolayo
    replied
    Thank you, Isomorphic! This will be very helpful.

    BTW, IMHO:
    1/ The data fields in CustomValidator should better be private rather than protected because they are under control of private methods.
    2/ The getter methods in CustomValidator should better be protected rather than public because the data they retrieve is only available during the execution of the condition() method.

    Let me also provide here some sample code for other interested readers:

    Sample custom validator:
    Code:
    import java.util.Date;
    
    /**
     * A sample custom validator. 
     */
    public class IsBeforeValidator
        extends CustomValidator
    {
        @Override
        protected boolean condition(Object value)
        {
            if (!(value instanceof Date)) {
                // The validator is bound to
                // a field of the wrong type.
                return false;
            }
            String target = getDataSourceValidator().getAttribute("target");
            if (target == null) {
                // May be typo or omission in the ds specs.
                // Don't let it fall through to the next stage 
                // where it would return true.
                return false;
            }
            Date targetValue = getRecord().getAttributeAsDate(target);
            if (targetValue == null) {
                // May be partial record where target value is not 
                // defined yet or may be that the target is optional.
                // So leave this to other validators to resolve.
                return true;
            }
            // The defining condition check at last:
            if (((Date) value).before(targetValue)) {
                return true;
            }
            else {
                return false;
            }
        }
    }
    Registration of the custom validator in the application entry point class:
    Code:
        static {
            Validator.addValidatorDefinition("isBefore", new IsBeforeValidator());
        }
    Binding of the custom validator to a field in a data source descriptor:
    Code:
    <field 
    	name="START_DATE"
    	type="date"
    	title="Start Date">
    	<validators>
    		<validator
    			type="isBefore"
    			clientOnly="true"
    			target="END_DATE"
    			errorMessage="Start date must be before end date!"/>
    			</validators>
    </field>
    The code above can work with current production version if custom Validator and CustomValidator classes are implemented and used. Here is source for those:

    Code:
    /**
     * Custom Validator class which adds addValidatorDefinition()
     * facility available in nightly builds but missing in released 
     * version 2.3 of smartgwtee. Be careful with the 2 Validator
     * classes and import the original in all places other than
     * the application entry point class where binding of custom
     * validators should happen.
     * 
    */
    //FIXME: remove this class as smartgwtee 2.4 gets published
    public class Validator
    {
        public native static void addValidatorDefinition(String name,
                                                         com.smartgwt.client.widgets.form.validator.Validator validator) /*-{
            if (validator == null) return;
            var jsValidator = validator.@com.smartgwt.client.widgets.form.validator.Validator::getJsObj()();
            if (jsValidator.errorMessage != null) jsValidator.defaultErrorMessage = jsValidator.errorMessage;
            $wnd.isc.Validator.addValidatorDefinition(name, jsValidator);
        }-*/;
    }
    Code:
    /**
     * Custom validator class which fixes lack of access to data source
     * validator definition in the original CustomValidator. There is 
     * some cost for the fix: private method setup() is called both
     * in the base class and in this one. Let's hope this or similar
     * fix will be implemented in the original sooner or later...<p/>
     *
     * Take care to change package name "com.sample.demo.client" 
     * in setup() if/when this class goes to another package!.
     */
    //FIXME: remove this class as the problem gets fixed in future
    //releases of smartgwtee beyond 2.3
    public abstract class CustomValidator
        extends com.smartgwt.client.widgets.form.validator.CustomValidator
    {
        private DataClass dataSourceValidator;
    
        public CustomValidator()
        {
            // type is set to "custom" by parent constructor 
            setup(getJsObj());
        }
    
        /**
         * Retrieve validator attributes defined in the data source descriptor(if any)
         * 
         * @return the attributes
         */
        protected DataClass getDataSourceValidator()
        {
            return dataSourceValidator;
        }
    
        private void reset()
        {
            formItem = null;
            dataSourceField = null;
            dataSourceValidator = null;
            record = null;
        }
    
        private native void setup(JavaScriptObject jsObj) /*-{
            var self = this;
            jsObj.condition = function(item, validator, value, record) {
                if($wnd.isc.isA.FormItem(item)) {
                   self.@com.smartgwt.client.widgets.form.validator.CustomValidator::formItem = @com.smartgwt.client.widgets.form.fields.FormItemFactory::getFormItem(Lcom/google/gwt/core/client/JavaScriptObject;)(item);
                } else {
                    if (item.__ref && @com.smartgwt.client.data.DataSourceField::isDataSourceField(Lcom/google/gwt/core/client/JavaScriptObject;)(item)) {
                        self.@com.smartgwt.client.widgets.form.validator.CustomValidator::dataSourceField = @com.smartgwt.client.data.DataSourceField::getOrCreateRef(Lcom/google/gwt/core/client/JavaScriptObject;)(item);
                    } else {
                        var dataSourceField = $wnd.isc.addProperties({}, item);
                        if (dataSourceField.__ref) delete dataSourceField.__ref;
                        self.@com.smartgwt.client.widgets.form.validator.CustomValidator::dataSourceField = @com.smartgwt.client.data.DataSourceField::new(Lcom/google/gwt/core/client/JavaScriptObject;)(dataSourceField);
                    }
                }
                if(record != null) {
                    self.@com.smartgwt.client.widgets.form.validator.CustomValidator::record = @com.smartgwt.client.data.Record::getOrCreateRef(Lcom/google/gwt/core/client/JavaScriptObject;)(record);
                }
                if(validator !=null) {
                    self.@com.sample.demo.client.CustomValidator::dataSourceValidator = @com.smartgwt.client.core.DataClass::new(Lcom/google/gwt/core/client/JavaScriptObject;)(validator);
                }
                else {
                    self.@com.sample.demo.client.CustomValidator::dataSourceValidator = @com.smartgwt.client.core.DataClass::new()();
                }
                var valueJ = $wnd.SmartGWT.convertToJavaType(value);
                var ret =  self.@com.smartgwt.client.widgets.form.validator.CustomValidator::condition(Ljava/lang/Object;)(valueJ);
                self.@com.smartgwt.client.widgets.form.validator.CustomValidator::reset()();
                return ret;
            };
        }-*/;
    }
    Regards
    Nikolay

    Leave a comment:


  • Isomorphic
    replied
    Hi nikolayo,

    Thanks for the clear analysis. We agree that the attributes specified on the validator definition (as defined directly on the dataSource field in javascript / xml) needs to be available to the live Java validator when the condition runs.

    We'll be addressing this in the near future (probably early next week).
    Thanks for the suggested approach and we'll keep you updated as soon as we have a resolution in place

    Regards
    Isomorphic Software

    Leave a comment:

Working...
X