Archive for the ‘Upshot’ Tag

ASP.NET MVC4/Upshot/Knockout: Remote + Local DataSource

The SPA (Single Page Application) I’m creating, does not sync all the changes with the server using the upshot RemoteDataSource. Because of that, I had to use a mixed approach, that is, a RemoteDataSource plus a LocalDataSource. The remote one brings the data from the server, while the local is used to make changes that will update the User interface, without going to the server. Here is the code:

// Used to "construct" new Model instances
function Model(data) {
    
	var self = this;

	// add properties from the JSON data result
	upshot.map(data, "SomeEntity:#SomeNamespace", self);

	// add properties managed by upshot
	upshot.addEntityProperties(self);
};

function ViewModel() {

	self = this;

	// Code generated by the Server-side @(Html.UpshotContext(true).DataSource<SomeNamespace.EntitiestController>(x => x.GetEntities()))
	upshot.metadata({ "SomeEntity:#SomeNamespace": { "key": ["Id"], "fields": { "Id": { "type": "String:#System" } }, "rules": {}, "messages": {}} });

	upshot.dataSources.Items = upshot.RemoteDataSource({
		providerParameters: { url: "/api/Entities?action=", operationName: "GetEntities" },
		entityType: "SomeEntity:#SomeNamespace",
		bufferChanges: true,
		dataContext: undefined,
		mapping: {}
	});

	// Creates a reference to the items returned by the remote datasource
	self.dataSource = upshot.dataSources.Items.refresh();

	// Create a local datasource that references the items returned by the remote datasource
	self.localDataSource = upshot.LocalDataSource({ source: self.dataSource,
		autoRefresh: true, allowRefreshWithEdits: true
	});	

        // Creates a filter to hide the deleted items (Since we are not syncing the changes, they will keep appearing on the UI otherwise)
        self.localDatasource.setFilter({ property: 'IsDeleted', value: false, operator: '==' });

	// Creates a reference to the local datasource entities to use it on the UI binds
	self.items = self.localDataSource.getEntities();

	self.addNew = function () {

		// Create a new item
		var item = new Model(null);

		// Pushes the item to the list of items. This will update the UI
		self.items.push(item);
	}

	self.remove = function (item) {
    
		// Removes the item from the localDatasource
		self.localDataSource.deleteEntity(item);

		// To update the UI, you have to refresh the local datasource (don't know why it does not do automatically)
		self.localDataSource.refresh();
	}
}

The autoRefresh property is self-explanatory. The important one here is the allowRefreshWithEdits property, that will allow us to execute refresh’s on the local datasource while having changes (it triggers an error if you don’t do this).

Another important thing is to add a filter to hide all the deleted entities at the local datasource. Since they are not commited to the server, they will still appear if you delete them and don’t apply a filter

Now, the user interface just have to bind to the items from the localDataSource, not the remote one:

<script type="text/javascript">
    $(function () {

        // Creates a ViewModel instance
        viewModel = new ViewModel();

        ko.applyBindings(viewModel);
    }
</script>
<div data-bind="foreach: items">
	<!-- Do something to show the items -->
<div>
Advertisements