Skip to content

Store Modify Method

Ralph Schaer edited this page Apr 14, 2020 · 15 revisions

Server

Create/Update

A method that handles create, update and destroy requests from a DirectStore is annotated with @ExtDirectMethod(value = ExtDirectMethodType.STORE_MODIFY). The method has either a parameter of type Collection OR a single object. Do not add two @ExtDirectMethod methods with the same name.

The return type is the same as the parameter or it has to be an instance of ExtDirectStoreResult when the reader is configured with a root property and the method returns only one instance of an object.

Example of a method with a collection as a parameter

      @ExtDirectMethod(value = ExtDirectMethodType.STORE_MODIFY)
      public List<Person> createOrUpdate(List<Person> newOrUpdatedPersons) {
        List<Person> result = Lists.newArrayList();
    
        for (Person person : newOrUpdatedPersons) {
          //for example insert/update person into database
          //set the id attribute if it's an insert and add it to the result collection
          result.add(person);
        }
    
        return result;
      }

Example of a method with one object as a parameter

      @ExtDirectMethod(value = ExtDirectMethodType.STORE_MODIFY)
      public Person createOrUpdate(Person person) {
        //insert or update person
        //set id if it's an insert
        return person;
      }

The data in the DirectStore will be updated after the server round-trip. Therefore the server method has the opportunity to change or reject data by simply returning changed data or
nothing. A common use case would be adding the primary key to the object after a database insert.

The decision to return a collection or a single object parameter depends on the use case on the client side. For example if autoSync on the Store is disabled the user can change multiple records without sending any data to the server. When he starts a manual sync the Store sends multiple records to the server. In this case the methods needs the Collection parameter to receive all the changed/inserted rows. On the other hand if autoSync is set to true the Store sends a request to the server every time the user updates or inserts a record In this case the server only get's one record at a time. The single object method is also appropriate if there is no store involved and the methods save() and destroy() from the Model class are used.

If the client specifies a root on the reader, and the method returns one instance of an object, this object has to be wrapped in an instance of ExtDirectStoreResult, and also the reciprocal is valid

    Ext.define('Person', {
      extend : 'Ext.data.Model',
      fields : ...,
      proxy : {
        type: 'direct',
        api: {
          ...
        },
        reader : {
          root : 'records'
        }
      }
    });
	@ExtDirectMethod(STORE_MODIFY)
	public ExtDirectStoreResult<User> create(User newUser) {
	    //do something with newUser
		return new ExtDirectStoreResult<>(newUser);
	}

The wrapping is not necessary when the method returns a collection. Ext JS handles this case correctly with or without the root property in the reader.

If a STORE_MODIFY method returns a wrapper object (like ExtDirectStoreResult or a custom object) the root property in the reader configuration must be specified and must match the name of the property in the wrapper class that holds the model object.

    public class MyResponse {
       private List<User> rows;
       public MyResponse(User user) {
          rows = new ArrayList<User>();
          rows.add(user);
       }
    }

    @ExtDirectMethod(ExtDirectMethodType.STORE_MODIFY)
    public MyResponse getUser() {
       User u = new User;		
       return new MyResponse(u);
    }
    Ext.define('User', {
      extend : 'Ext.data.Model',
      ....
      proxy : {
       type: 'direct',
        api: {
          ....
        },
        reader : {
         root : 'rows'
        }
      }
    });

Destroy Ext JS 3.x

Compared to create and update methods a destroy method only receives a collection with the ids and returns a collection with ids.

      @ExtDirectMethod(value = ExtDirectMethodType.STORE_MODIFY, entryClass = Integer.class)
      public List<Integer> destroy(List<Integer> destroyIds) {
        List<Integer> deletedPersonsId = Lists.newArrayList();
    
        for (Integer id : destroyIds) {
          ...
          deletedPersonsId.add(id);
        }
    
        return deletedPersonsId;
      }

The method can veto the destroy request by returning an empty collection.

Destroy Ext JS 4.x and Sencha Touch 2

The way destroy methods work changed with Ext JS 4.x. The client now sends the whole object to the server like in the Create and Update methods. It also looks like there is no way to veto the destroy method any more. Although the server can simply ignore the delete request, but the user does not see the record anymore on the client side, as long he's not reloading the data.

    @ExtDirectMethod(STORE_MODIFY)	
    public void destroy(List<User> destroyUsers) {
      for (User user : destroyUsers) {
        //delete the user from the persistent storage 
        //or ignore the request
      }
    }

Client Ext JS 3.x

On the client we need an instance of a JsonWriter. The listful property of the JsonWriter must be set to true. This way the writer always sends a list to the server even if there is only one insert, update or destroy record. Also the encode property must have the value false. If the writeAllFields is true all fields of a record will be sent to the server, if false only the changed fields are transmitted.

      var writer = new Ext.data.JsonWriter( {
        writeAllFields: true,
        listful: true,
        encode: false
      });

The create/read/update/delete methods are specified in the api configuration.

      var directStore = new Ext.data.DirectStore( {
        id: 'directStore',
        paramsAsHash: true,
        root: 'records',
        totalProperty: 'total',
        autoLoad: false,
        autoSave: true,
        successProperty: 'success',
        fields: ['id', 'firstName', 'lastName'],
        remoteSort: true,
        idProperty: 'id',
        writer: writer,
        api: {
          read: personAction.load,
          create: personAction.createOrUpdate,
          update: personAction.createOrUpdate,
          destroy: personAction.destroy
        }
      });

Client Ext JS 4.x and Sencha Touch 2

Configuring a DirectStore changed in Ext JS 4.x. It's still possible to specify everything in the store configuration but the prefered solution is to create a model class with a proxy configuration.

    Ext.define('Person', {
      extend : 'Ext.data.Model',
      fields : [ 'id', 'firstName', 'lastName' ],
      proxy : {
       type: 'direct',
        api: {
          read: personAction.load,
          create: personAction.createOrUpdate,
          update: personAction.createOrUpdate,
          destroy: personAction.destroy
        },
        reader : {
         root : 'records'
        }
      }
    });
    
    var store = Ext.create('Ext.data.Store', {
      autoLoad: false,
      autoSave: true,
      model : 'Person'
    });
Clone this wiki locally