神刀安全网

Couchbase Mobile in a Cross Platform Telerik NativeScript App

From a personal level, I’m a huge fan of Telerik NativeScript . It is a cross platform development framework for building native Android and iOS applications using a single codeset, that code set being JavaScript. I had to put emphasis on the native part because it is one of the only cross platform frameworks that does not use a web view for displaying content. This in turn creates an application that has incredible performance.

Up until now there hasn’t been a good solution for storing data in a NativeScript app. That is until now!

Couchbase Mobile in a Cross Platform Telerik NativeScript App

With the help of Telerik and the NativeScript team, I was able to come up with a Couchbase Lite plugin for NativeScript that allows you to leverage the power of NoSQL in your mobile application. When paired with Couchbase Sync Gateway, data can be synchronized between devices and platforms.

We’re going to see what it takes to get started withCouchbase Mobile in your NativeScript app.

The Requirements

There are a few requiements to make this possible.

  • NativeScript 1.7+
  • The Android SDK (if building Android apps)
  • Xcode and a Mac (if building iOS apps)
  • Couchbase Sync Gateway (for sync)

You don’t need to build for both Android and iOS, but it certainly is convenient.

Creating a New NativeScript Project

We’re going to build a simple name list application that synchronizes between devices. To do this, execute the following from a Command Prompt (Windows) or Terminal (Mac and Linux):

 tns create CouchbaseProject cd CouchbaseProject tns platform add ios tns platform add android 

Remember, if you’re not using a Mac, you cannot add and build for the iOS platform. Going forward, the Command Prompt or Terminal should use CouchbaseProject as the working directory.

Including the Couchbase Lite SDK

With the project created it is time to include the Couchbase Lite plugin for use. From the Terminal or Command Prompt, execute the following:

 tns plugin add nativescript-couchbase 

This will include the plugin for whatever platforms that have been added to the project.

Developing the Application

With the project created we need to create a few files and directories. Go ahead and add the following:

 mkdir app/views mkdir app/views/list mkdir app/views/create touch app/views/list/list.js touch app/views/list/list.xml touch app/views/create/create.js touch app/views/create/create.xml 

The above files is where we are going to spend most of our time, but before we jump in, open the project’s app/app.js file and switch out the appropriate line with the following:

 application.start({ moduleName: "views/list/list" }); 

This tells the NativeScript application that the list view will be our first view.

Creating the Application Logic

The application logic files are the JavaScript files. One file will drive the logic behind our list view and the other will drive the logic behind our name creation form. Starting with the list logic, open the project’s app/views/list/list.js file and include the following code:

 var couchbaseModule = require("nativescript-couchbase"); var observableArrayModule = require("data/observable-array"); var frameModule = require("ui/frame");  var database; var personList;  function pageLoaded(args) {     var page = args.object;      personList = new observableArrayModule.ObservableArray([]);     database = new couchbaseModule.Couchbase("test-database");      database.createView("people", "1", function(document, emitter) {         emitter.emit(JSON.parse(document)._id, document);     });      refresh();     page.bindingContext = {personList: personList}; }  function refresh() {     personList.splice(0);      var rows = database.executeQuery("people");      for(var i in rows) {           if(rows.hasOwnProperty(i)) {               personList.push(JSON.parse(rows[i]));           }     } }  function create() {     frameModule.topmost().navigate({moduleName: "views/create/create"}); }  exports.pageLoaded = pageLoaded; exports.refresh = refresh; exports.create = create; 

There is a lot happening in the above logic file so we’re going to break it down. First thing we’re doing is including a few JavaScript libraries:

 var couchbaseModule = require("nativescript-couchbase"); var observableArrayModule = require("data/observable-array"); var frameModule = require("ui/frame"); 

The plugin that was installed must first be imported. All data read from the database will be stored in an observable array. This is so we can subscribe to data changes and bind the data to the UI. Finally the frame is imported so we can navigate to other pages.

To open a particular Couchbase NoSQL database we would execute the following command:

 database = new couchbaseModule.Couchbase("test-database"); 

The above command will open the database if it exists or it will create and open the database if it does not exist.

 database.createView("people", "1", function(document, emitter) {     emitter.emit(JSON.parse(document)._id, document); }); 

If this is your first time working with NoSQL, the above snippet might look very foreign. It is the creation of a MapReduce view. Instead of writing a SQL statement as seen in SQLite, we’re creating MapReduce views that we can query for data. The above view will return a key-value pair of all documents where the key is the document id and the value is the document itself. This view is going to be called people .

With the view in place, it needs to be queried. This is done through the refresh function. Before getting to the refresh function, notice the final line of the pageLoaded function. This shows that we’ll be binding the personList data to our UI. Let’s look at that refresh function:

 function refresh() {     personList.splice(0);      var rows = database.executeQuery("people");      for(var i in rows) {           if(rows.hasOwnProperty(i)) {               personList.push(JSON.parse(rows[i]));           }     } } 

Every time we query the list will be reset and re-populated. The view will only be queried when the page loads. We’ll see why further down in this tutorial.

With the app/views/list/list.js file out of the way we can focus on the logic file behind the creation form. Open the project’s app/views/create/create.js file and include the following code:

 var couchbaseModule = require("nativescript-couchbase"); var observableArrayModule = require("data/observable-array"); var frameModule = require("ui/frame");  var database; var tfFirstName; var tfLastName;  function pageLoaded(args) {     var page = args.object;      personList = new observableArrayModule.ObservableArray([]);     database = new couchbaseModule.Couchbase("test-database");      tfFirstName = page.getViewById("firstname");     tfLastName = page.getViewById("lastname");      page.bindingContext = {}; }  function save() {     database.createDocument({         "firstname": tfFirstName.text,         "lastname": tfLastName.text     });     frameModule.goBack(); }  exports.pageLoaded = pageLoaded; exports.save = save; 

This file is a lot more lightweight in comparison to the last. Essentially we’re capturing the form elements that we’ve yet to create. When we call the save function it will take the values in the form fields and create the document in Couchbase. No SQL schemas or nonsense to slow you down when it comes to development. One of the major benefits to using NoSQL.

The logic is now complete, for now, and we can move onto the UI.

Designing a Cross Platform UI

The UI code is short and sweet. Remember, our list will only contain information about the users we add. Open the project’s app/views/list/list.xml file and include the following code:

 <Page loaded="pageLoaded">     <Page.actionBar>   <ActionBar title="People">    <ActionBar.actionItems>     <ActionItem text="Create" tap="create" ios.position="right" />    </ActionBar.actionItems>   </ActionBar>  </Page.actionBar>     <ListView items="{{ personList }}">         <ListView.itemTemplate>             <StackLayout>                 <Label text="{{ (firstname + ' ' + lastname) }}" />             </StackLayout>         </ListView.itemTemplate>     </ListView> </Page> 

When the page loads, it calls the pageLoaded function. The action bar has a single button for navigating to the create page. Finally the list view will iterate over the personList observable array that was created in the logic file.

When it comes to the create form, there is similarly a small amount of XML code to be included. Open the project’s app/views/create/create.xml file and include the following code:

 <Page loaded="pageLoaded">     <Page.actionBar>   <ActionBar title="New Person">    <ActionBar.actionItems>     <ActionItem text="Save" tap="save" ios.position="right" />    </ActionBar.actionItems>   </ActionBar>  </Page.actionBar>     <StackLayout>         <Label text="First Name" />         <TextField id="firstname" />         <Label text="Last Name" />         <TextField id="lastname" />     </StackLayout> </Page> 

Again the pageLoaded is called on page load. The action bar has a single button for saving the Couchbase data, and the form contains data that is read via the logic file that we previously created.

We should have a fully functional app that uses Couchbase for storing data. However, as of right now this application is offline only. Data is not being synchronized.

Including Couchbase Sync Gateway for Data Replication

To synchronize the application data between Couchbase Server and other devices, the Couchbase Sync Gateway must be included along with a special configuration file. To keep things simple here, we are not going to go in depth when it comes to a Sync Gateway configuration file. Something like this will suffice:

 {     "log":["CRUD+", "REST+", "Changes+", "Attach+"],     "databases": {         "test-database": {             "server":"walrus:",             "sync":`                 function (doc) {                     channel (doc.channels);                 }             `,             "users": {                 "GUEST": {                     "disabled": false,                     "admin_channels": ["*"]                 }             }         }     } } 

What matters to us for this tutorial is the code that communicates with the Sync Gateway via our application. We’re now going to revisit the app/views/list/list.js file and include some code in the pageLoaded function. Open the file and include the following:

 var push = database.createPushReplication("http://localhost:4984/test-database"); var pull = database.createPullReplication("http://localhost:4984/test-database");  push.setContinuous(true); pull.setContinuous(true);  push.start(); pull.start(); 

In the above we are telling our application that we are going to push and pull from the same Sync Gateway that is being run locally. Replications are going to happen continuously in both directions. Then we finally start the process.

With data being uploaded and downloaded we need a way to update the UI when necessary. Previously I mentioned we were only querying one time when the page loads. This is because we’re actually going to use a listener to listen for changes. It is more efficient than continously querying for potentially massive amounts of data. Inside your app/views/list/list.js file, within the pageLoaded function, include the following code:

 database.addDatabaseChangeListener(function(changes) {     var changeIndex;     for(var i = 0; i < changes.length; i++) {         var documentId;          documentId = changes[i].getDocumentId();         changeIndex = indexOfObjectId(documentId, personList);         var document = database.getDocument(documentId);          if(changeIndex == -1) {             personList.push(document);         } else {             personList.setItem(changeIndex, document);         }     } }); 

The goal here is to pick up a change, see if that document already exists in the list, if it doesn’t, add it, otherwise, change it. The function for finding where a document exists in the list can be seen below:

 function indexOfObjectId(needle, haystack) {     for(var i = 0; i < haystack.length; i++) {         if(haystack.getItem(i) != undefined && haystack.getItem(i).hasOwnProperty("_id")) {             if(haystack.getItem(i)._id == needle) {                 return i;             }         }     }     return -1; } 

Maybe not the most efficient way to update a list view, but it works for this example.

Couchbase Mobile in a Cross Platform Telerik NativeScript App

At this point if you run the Sync Gateway and your application, it should synchronize the data.

Conclusion

You just saw how to create a simple cross platform, native , Android and iOS application that syncs using NativeScript and the Couchbase Lite plugin. Further information about the plugin can be seen on the project’s GitHub page. More on Couchbase Mobile can be seen in the Couchbase Developer Portal .

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Couchbase Mobile in a Cross Platform Telerik NativeScript App

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮