Announcement

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

    Many-to-One relationship and combobox

    Hi, all.

    For example, I have two entities linked in many-to-one way:
    Person(id@Long, firstname@String, surname@String) and Project(id@Long, name@String, managerId@Long, manager@Person).
    Here Project.managerId is a foreignKey to Person.id and Project.manager is a Person object.
    Also I have ListGrid of Projects and DynamicForm with Person combobox for addition and editing Project records.

    For editing record I show Window and call DynamicForm.editRecord(record).
    After that Smartclient pull Person data from server, but all necessary data is at client side already!
    So I've got a question. Is it possible use Project.person record for combobox without extra request to the server?
    My code is below
    Code:
    isc.DataSource.create({
    	ID : 'personDS',
    	dataURL : '/testproject/person',
    	dataFormat : 'json',
    	fields : [ {
    		name : 'id',
    		type : 'integer',
    		primaryKey : true,
    		hidden : true
    
    	}, {
    		name : 'fullName',
    		type : 'string'
    	} ],
    	operationBindings : [ {
    		operationType : 'fetch',
    		dataProtocol : 'getParams',
    	} ]
    
    });
    
    isc.DataSource.create({
    	ID : 'projectDS',
    	dataURL : '/testproject/project',
    	dataFormat : 'json',
    	fields : [ {
    		name : 'id',
    		type : 'integer',
    		primaryKey : true,
    		hidden : true
    	}, {
    		name : 'name',
    		type : 'string'
    	}, {
    		name : 'managerId',
    		type : 'integer',
    		foreignKey : 'personDS.id',
    	}, {
    		name : 'manager',
    		type : 'personDS',
    		hidden : true
    
    	} ],
    	operationBindings : [ {
    		operationType : 'fetch',
    		dataProtocol : 'getParams',
    	}, {
    		operationType : 'add',
    		dataProtocol : 'postParams',
    	}, {
    		operationType : 'update',
    		dataProtocol : 'postParams',
    		requestProperties : {
    			httpMethod : 'PUT'
    		}
    	} ]
    
    })
    
    isc.defineClass('ProjectWindow', 'Window').addProperties({
    	width : 300,
    	height : 300,
    	autoDraw : true,
    	initWidget : function() {
    		this.Super('initWidget', arguments);
    		this.addItems([ DynamicForm.create({
    			ID : 'projectDynamicForm',
    			dataSource : 'projectDS',
    			useAllDataSourceFields : true,
    			fields : [ {
    				name : 'managerId',
    				editorType : 'ComboBoxItem',
    				optionDataSource : 'personDS',
    				displayField : 'fullName',
    				valueField : 'id',
    				autoFetch : true,
    				addUnknownValues : false,
    				minimumSearchLength : 4,
    				pickListWidth : 300
    			} ]
    		}), Button.create({
    			title : 'save',
    			click : function() {
    				projectDynamicForm.saveData();
    			}
    		}) ]);
    	}
    })
    
    VLayout.create({
    	width : 600,
    	height : 300,
    	members : [ Button.create({
    		title : 'Add',
    		autoDraw : true,
    		click : function() {
    			ProjectWindow.create()
    		}
    	}),
    
    	ListGrid.create({
    		autoDraw : true,
    		dataSource : 'projectDS',
    		autoFetchData : true,
    		useAllDataSourceFields : true,
    		showRecordComponents : true,
    		showRecordComponentsByCell : true,
    		fields : [ {
    			name : 'actions',
    		} ],
    		createRecordComponent : function(record, colNum) {
    			if (colNum == 0) {
    				return Button.create({
    					title : 'Edit',
    					click : function() {
    						ProjectWindow.create();
    						projectDynamicForm.editRecord(record)
    					}
    				})
    			}
    		}
    	}) ]
    })
    Last edited by rodionstl; 10 Feb 2015, 03:27.

    #2
    Yes, if you're returning the Person record along with the Project in your JSON, you can access it on a Project record using normal JavaScript syntax: Project.person.

    However you should carefully consider whether it makes sense to load the Person record every time you load the Project record. If you are searching through a list of 100s of Projects in the UI, and will only look at the Person record for 1 or 2 of them, then in makes more sense to just load the Person record on demand.

    Comment


      #3
      Thanks a lot for your reply! Unfortunately I still have questions.

      1) Calling by hand ComboBoxItem.setValue(record.managerId) causes extra request to server for person data. I guess the same method are invoked in DynamicForm.editRecord. How should I configure DataSources to disable it?
      2) If I call this method with record.manger parameter (object of Person) that SmartClient also try sent request to the server and display [object Object] in field. What I do wrong?

      Can you give some piece of code or documentation link?

      Comment


        #4
        See DataSourceField.includeFrom for advice on how best to expose attributes of a related record. You don't seem to be using our server, so you would be able to use includeFrom directly, but you should follow the pattern of how it's implemented.

        Comment


          #5
          This is response from server:
          Code:
          [
              {
                  "id": 1,
                  "name": "project 1",
                  "personId": 123,
                  "person": {
                      "id": 111,
                      "fullName": "John Smith",
                  }
              },
              {
                  "id": 2,
                  "name": "project 2",
                  "personId": 456,
                  "person": {
                      "id": 222,
                      "fullName": "Jack Williams",
                  }
              }
          ]

          This is configuration of fields of projectDS:
          Code:
          	fields : [ {
          		name : 'id',
          		type : 'integer',
          		primaryKey : true,
          		hidden : true
          	}, {
          		name : 'name',
          		type : 'string'
          	}, {
          		name : 'personId',
          		type : 'integer',
          		foreignKey : 'personDS.id',
          		displayField : 'personFullName'
          	}, {
          		name : 'personFullName',
          		type : 'string',
          		includeFrom : 'personDS.fullName', //or person.fullName ?
          		hidden : true
          	}, {
          		name : 'person',
          		type : 'personDS',
          		hidden : true
          	} ],
          It doesn't work. Where is mistake?
          Last edited by rodionstl; 11 Feb 2015, 00:00.

          Comment


            #6
            As I understand there are two approaches.
            The first is to describe plain model with foreignKey. The second one is describe nested model with included objects instead of (or together with) foreignKey.

            The first way has more disadvantage than advantages.
            Firstly, it is necessary to implement services on server side for loading all entities by foreignKey (It isn't' always simple).
            Secondly, all services is loaded in different time. And when I show window it is necessary synchronize loading proccess for enabling window and unmask it.
            Thirdly, If I have grid with 20 records and every record has 5 foreignKey then 100 request will be sent to the server. (But there is valueXPath for grid and it works. But it works for grid and not for combobox'd form)

            I try realize the second approach with nested model. I read docs and tryed various DataSource configuration but I don't achieve success.

            Can you say is it possible what I want at all?

            Comment


              #7
              Independent loading of data is by far the preferable and more capable approach. It allows you to use paging of detail records when there are many thousands of records.

              Your example of loading all related detail records for 20 master records doesn't make any sense - not only is this not a realistic scenario for an actual UI, but if it came up, you could load all the detail records in a single call by either identifying them by their foreignKey values using criteria, or by using Queuing (see QuickStart Guide).

              If, even after this discussion, you really really think you're in a situation where nested records make sense, and you're having trouble implementing it despite the docs that cover it and the help you've had here so far, consider purchasing support or training to get more hands-on help.

              Comment

              Working...
              X