{"id":3673,"date":"2017-06-05T02:03:15","date_gmt":"2017-06-05T09:03:15","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=3673"},"modified":"2023-06-19T02:15:21","modified_gmt":"2023-06-19T09:15:21","slug":"persist-abstract-data-nativescript-typescript-application","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/","title":{"rendered":"Persist and Abstract Data in a Nativescript Typescript Application"},"content":{"rendered":"<p><a href=\"https:\/\/www.linkedin.com\/in\/aaron-ullal\/\">Aaron Ullal<\/a> is a\u00a0<em>Freelance developer at FactoryMind, people &amp; life lover, living in permanent beta. \u00a0He<\/em><em>\u00a0<\/em><em>is a full stack developer based in the beautiful town of Trento, Italy.<\/em><\/p>\n<p><em>IT passionate for more <\/em><em>than <\/em><em>7 years, he&#8217;s <\/em><em>currently<\/em><em>\u00a0focused on mobile development using Native<\/em><em>S<\/em><em>cript and designing architectural solutions for complex platforms.<\/em><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-3682\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/06\/AaronUllal-300x200.png\" alt=\"Aaron Ullal \" width=\"300\" height=\"200\" srcset=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/06\/AaronUllal-300x200.png 300w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/06\/AaronUllal-400x267.png 400w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/06\/AaronUllal-450x300.png 450w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/06\/AaronUllal-20x13.png 20w, https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2017\/06\/AaronUllal.png 600w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Couchbase is a great tool to persist data inside our app. If you haven\u2019t heard of it, it\u2019s a document object storage that allows you to save your data.<\/p>\n<p>If you are using NativeScript-Angular, there are already some great tutorials on how to get started and some more advanced features. In this article we\u2019ll focus on NativeScript with TypeScript.<\/p>\n<p><strong>What we\u2019ll cover<\/strong><\/p>\n<p>In this simple article we will see how to save and retrieve some user information by:<\/p>\n<ol>\n<li>Installing\u00a0Couchbase<\/li>\n<li>Creating a TypeScript class that provides a layer of abstraction on top of Couchbase, making it a lot more easy to use (no complex instructions for data insertion and retrieval)<\/li>\n<li>Implementing the singleton pattern on the class<\/li>\n<\/ol>\n<p>By the end of the tutorial we\u2019ll be able to use instructions such as<\/p>\n<pre class=\"lang:default decode:true\">userSettings.name =\u00a0\"Frank\"\u00a0\/\/boom! written in our db\r\n\r\ntext=\u201d{{\u00a0userSettings.name }}\u201d\u00a0\/\/boom! read from our db<\/pre>\n<p>without having to write extensive queries to read and write!<\/p>\n<p>Also, all of the code in this article is available in <u><a href=\"https:\/\/github.com\/ullalaaron\/nativescript-couchbase-demo\" target=\"_blank\" rel=\"noopener noreferrer\">this<\/a><\/u>\u00a0GitHub repo. Feel free to clone it and play around.<\/p>\n<p>Without further ado, let\u2019s get started!<\/p>\n<p><strong>Install Couchbase plugin<\/strong><\/p>\n<p>Let\u2019s create a new NativeScript app using the TypeScript template.<\/p>\n<pre class=\"lang:default decode:true\">tns create ns-couchbase-demo --tsc<\/pre>\n<p>In the root folder of our newly created NativeScript project, let\u2019s give the following command to add the plugin and save it to our dependencies list:<\/p>\n<pre class=\"lang:default decode:true\">tns plugin add nativescript-couchbase\r\n\r\n<\/pre>\n<p>Once the plugin is successfully installed, let\u2019s create a class that we\u2019ll use to store and retrieve the user information we need.<\/p>\n<p><strong>Abstraction layer class<\/strong><\/p>\n<p><strong>OPTIONAL: <\/strong>It is usually a good idea to create an interface to define the properties we need to include.<\/p>\n<p>Navigate to the app\u00a0folder of our project and create a models\u00a0folder. Here we will define our Models.ts file \u00a0(app\/models\/Models.ts):<\/p>\n<pre class=\"lang:default decode:true\">export\u00a0module\u00a0Models{\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0export\u00a0interface\u00a0IUserSettings\u00a0{\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0username :string;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0fullname :string;\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0email :string;\r\n\r\n}\r\n\r\n}\r\n\r\n<\/pre>\n<p>Once we defined our interface, let\u2019s go ahead and create the class that actually implements it. We\u2019ll call the class UserSettings.<\/p>\n<p>Inside this class we also need to store the information related to our Couchbase database.<\/p>\n<pre class=\"lang:default decode:true \">let CouchBaseModule\u00a0=\u00a0require(\"nativescript-couchbase\");\r\n\r\nimport\u00a0{\u00a0Models\u00a0}\u00a0from\u00a0'..\/models\/Models';\r\n\r\nexport\u00a0class\u00a0UserSettings implements Models.IUserSettings{\r\n\r\n\u00a0 \u00a0private\u00a0DATABASE_NAME =\u00a0'appname-db';\r\n\r\n\u00a0 \u00a0private\u00a0USER_SETTINGS_DOC_ID\u00a0=\u00a0'usersettings';\r\n\r\n\u00a0 \u00a0private\u00a0_database;\r\n\r\n\u00a0 \u00a0private\u00a0_userSettingsDocument:\u00a0Models.IUserSettings;\r\n\r\n\u00a0 \u00a0private\u00a0_userSettingsObj:\u00a0Models.IUserSettings;\r\n\r\n\u00a0 \u00a0private _instance :UserSettings;\r\n\r\n}\r\n\r\n<\/pre>\n<p>Let\u2019s break it down:<\/p>\n<p>In the first two lines we require the Couchbase plugin we previously installed along with the Models module we will use to take advantage of TypeScript\u2019s strong typing.<\/p>\n<p>Then we define some other private properties that we\u2019ll use later:<\/p>\n<p>DATABASE_NAME: This is the name of the database. Make sure it doesn\u2019t contain capital letters\u00a0(and it\u2019s less than 240 characters).<\/p>\n<p>USER_SETTINGS_DOC_ID: Name of the Couchbase document.<\/p>\n<p>database: This is the instance of the database connector.<\/p>\n<p>_userSettingsDocument: Couchbase is a No document-oriented database. It does not have tables, instead it uses a primary storage entity known as Document. Basically a document is a collection of key-value pairs, where the value can be pretty much anything (string, numbers, arrays, etc.). This is what makes Couchbase the number one solution if you need to store a variety of non-relational data: simplicity and flexibility.<\/p>\n<p>_userSettingsObj: This is the JavaScript object that we will use to sync the information with the Couchbase document.<\/p>\n<p>We will cover why we declared the\u00a0_instance\u00a0variable later on when we implement the singleton pattern.<\/p>\n<p>Now that we\u2019ve got that covered, let\u2019s see how our class constructor works:<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"lang:default decode:true \">constructor()\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0this._database =\u00a0new\u00a0CouchBaseModule.Couchbase(this.DATABASE_NAME);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0this._userSettingsDocument =\u00a0this._database.getDocument(this.USER_SETTINGS_DOC_ID);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0if\u00a0(!this._userSettingsDocument)\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0console.log(\"Document does not exist yet :)\");\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0this._userSettingsObj =\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0username:\u00a0\"\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0email:\u00a0\"\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0fullname:\u00a0\"\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0}\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0this._database.createDocument(this._userSettingsObj,\u00a0this.USER_SETTINGS_DOC_ID);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0this._userSettingsDocument =\u00a0this._database.getDocument(this.USER_SETTINGS_DOC_ID);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0}\r\n\r\n\u00a0 \u00a0}\r\n\r\n<\/pre>\n<p>Once again, let\u2019s see in detail what\u2019s going on in our constructor:.<\/p>\n<p>this._database =\u00a0new\u00a0CouchBaseModule.Couchbase(this.DATABASE_NAME);<\/p>\n<p>Here we are instantiating Couchbase and telling to which database we want to connect.<\/p>\n<p>this._userSettingsDocument =\u00a0this._database.getDocument(this.USER_SETTINGS_DOC_ID);<\/p>\n<p>This line tells Couchbase to get us our document (the collection which we use to store our info).<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"lang:default decode:true \">\u00a0if\u00a0(!this._userSettingsDocument)\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0console.log(\"Document does not exist yet :)\");\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0this._userSettingsObj =\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0username:\u00a0\"\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0email:\u00a0\"\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0fullname:\u00a0\"\",\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0}\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0this._database.createDocument(this._userSettingsObj,\u00a0this.USER_SETTINGS_DOC_ID);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0this._userSettingsDocument =\u00a0this._database.getDocument(this.USER_SETTINGS_DOC_ID);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0}<\/pre>\n<p>&nbsp;<\/p>\n<p>If our document doesn\u2019t exist yet (e.g., first time), we create an empty Object of type UserSettings and we also create a new document. The second parameter we assign to the createDocument function is the id of the document. If we don\u2019t supply this parameter Couchbase will assign the document a UUID automatically.<\/p>\n<p>Fantastic! Now that our constructor is done, let\u2019s see how we can set and retrieve information about our user.<\/p>\n<p>We\u2019ll set up some getters and setters to achieve just that.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"lang:default decode:true \">\/*====== USERNAME GETTER AND SETTER ======*\/\r\n\r\n\u00a0 \u00a0get\u00a0username():\u00a0string\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0this._userSettingsObj =\u00a0this._database.getDocument(this.USER_SETTINGS_DOC_ID\r\n\r\n);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0let username =\u00a0this._userSettingsObj.username;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0return\u00a0username;\r\n\r\n\u00a0 \u00a0}\r\n\r\n\u00a0 \u00a0set\u00a0username(value:\u00a0string)\u00a0{\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0this._userSettingsObj =\u00a0this._database.getDocument(this.USER_SETTINGS_DOC_ID\r\n\r\n);\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0this._userSettingsObj.username =\u00a0value;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0this._database.updateDocument(this.USER_SETTINGS_DOC_ID\r\n\r\n,\u00a0this._userSettingsObj);\r\n\r\n\u00a0 \u00a0}<\/pre>\n<p>As usual, let\u2019s break the code down.<\/p>\n<p>In the getter we do three things:<\/p>\n<p>1) We read data from our document into our object<\/p>\n<p>2) Get the desired value (in this case the username)<\/p>\n<p>3) Return it<\/p>\n<p>Easy peasy :)<\/p>\n<p>In the setter we do the following:<\/p>\n<p>1) We get the latest version of our userSettingsObject reading it from the db<\/p>\n<p>2) We set the username property to the value passed to the function<\/p>\n<p>3) We update our document in the database. Contrary to the createDocument function, the first parameter is the ID of the document and the second is the object itself.<\/p>\n<p>But \u2026 why do we need to getDocument first? Why can\u2019t we just update the document with the object?<\/p>\n<p>I\u2019m glad you asked!<\/p>\n<p>Basically, whenever we update a document, Couchbase keeps track of the change. Each document has a _rev property; this value gets updated by Couchbase every time a write operation on the document takes place. If we try to update a document with a an older _rev, Couchbase will reject it.<\/p>\n<p><strong>Singleton pattern<\/strong><\/p>\n<p>Who doesn\u2019t love design patterns? Today we\u2019ll go ahead and implement a very simple, yet effective one: the singleton. The singleton pattern, when correctly implemented, \u201crestricts the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Instantiation_(computer_science)\" target=\"_blank\" rel=\"noopener noreferrer\">instantiation<\/a>\u00a0of a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Class_(computer_programming)\" target=\"_blank\" rel=\"noopener noreferrer\">class<\/a>\u00a0to one <a href=\"https:\/\/en.wikipedia.org\/wiki\/Object_(computer_science)\" target=\"_blank\" rel=\"noopener noreferrer\">object<\/a>. This is useful when exactly one object is needed to coordinate actions across the system,\u201d \u00a0which is exactly our case.<\/p>\n<p>Basically we make sure that we only have one instance of our class reading and writing to our database.<\/p>\n<p>How do we do that? A simple way to achieve that is with the following two\u00a0steps:<\/p>\n<p>1)\u00a0Making our constructor private (Introduced in ts 2.0)<\/p>\n<p>2)\u00a0Implementing a getInstance method which returns the current instance if it exists, or a new one if it\u2019s the first call<\/p>\n<p>STEP 1:<\/p>\n<pre class=\"lang:default decode:true \">private\u00a0constructor()\u00a0{....}\r\n\r\n<\/pre>\n<p>STEP 2:<\/p>\n<p>Now we can go ahead and create our\u00a0getInstance()\u00a0method which will look something like this:<\/p>\n<pre class=\"lang:default decode:true \">public\u00a0static\u00a0getInstance()\u00a0:UserSettings{\r\n\r\n\u00a0 \u00a0if(!this._instance){\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 this._instance =\u00a0new\u00a0UserSettings();\r\n\r\n\u00a0 \u00a0 }\r\n\r\nreturn\u00a0this._instance;\r\n\r\n}\r\n\r\n<\/pre>\n<p>Great! We have abstracted data and implemented the singleton pattern, let\u2019s go ahead and see how we can use our shiny new UserSettings\u00a0class.<\/p>\n<p>We will be editing the existing\u00a0main-page.xml and main-page.ts\u00a0files.<\/p>\n<p>First, we\u2019ll define some basic UI layout. For this demo we\u2019ll be using \u00a0a textfield to get user input, a button to save the value to the db, and a label to display the current value in the database. As you can see, if no data is stored in the database the label will simply display \u201cNo data stored in the db.\u201d<\/p>\n<p>This is what our main-page.xml\u00a0file should look like:<\/p>\n<pre class=\"lang:default decode:true \">&lt;Page xmlns=\"https:\/\/schemas.nativescript.org\/tns.xsd\" navigatingTo=\"navigatingTo\"&gt;\r\n\r\n\u00a0 \u00a0 &lt;Page.actionBar&gt;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 &lt;ActionBar title=\"My App\" icon=\"\" class=\"action-bar\"&gt;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 &lt;\/ActionBar&gt;\r\n\r\n\u00a0 \u00a0 &lt;\/Page.actionBar&gt;\r\n\r\n\u00a0 \u00a0 &lt;StackLayout&gt;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 &lt;TextField hint=\"username\" text=\"{{ username }}\" \/&gt;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 &lt;Button text=\"SAVE MY USERNAME\" tap=\"onTap\" class=\"btn btn-primary btn-active\"\/&gt;\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 &lt;Label text=\"{{ dbusername || 'no data stored in the db' }}\" textWrap=\"true\"\/&gt;\r\n\r\n\u00a0 \u00a0 &lt;\/StackLayout&gt;\r\n\r\n&lt;\/Page&gt;\r\n\r\n<\/pre>\n<p>Alright! Now that we\u2019ve got a basic layout we can proceed by adding some logic to the UI.<\/p>\n<p>This is how our main-page.ts file should look:<\/p>\n<pre class=\"lang:default decode:true \">import\u00a0{\u00a0Observable\u00a0}\u00a0from\u00a0'data\/observable'; \/\/bind data to our view\r\n\r\nimport\u00a0{\u00a0UserSettings\u00a0}\u00a0from\u00a0'.\/UserSettings'; \/\/woohoo our amazing database interaction layer\r\n\r\nimport\u00a0{\u00a0EventData\u00a0}\u00a0from\u00a0'data\/observable'; \/\/use with typescript for intellisense\r\n\r\nimport\u00a0{\u00a0Page\u00a0}\u00a0from\u00a0'ui\/page'; \/\/use with typescript for intellisense\r\n\r\nlet userSettings =\u00a0UserSettings.getInstance();\r\n\r\nlet mainPageViewModel;\r\n\r\nclass\u00a0MainPageViewModel\u00a0extends\u00a0Observable{\r\n\r\n\u00a0 \u00a0 public\u00a0username;\r\n\r\n\u00a0 \u00a0 public\u00a0dbusername\r\n\r\n\u00a0 \u00a0 constructor(){\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 super();\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.dbusername =\u00a0userSettings.username;\r\n\r\n\u00a0 \u00a0 }\r\n\r\n}\r\n\r\nexport\u00a0function\u00a0navigatingTo(args:\u00a0EventData)\u00a0{\r\n\r\n\u00a0 \u00a0 let page =\u00a0&lt;Page&gt;args.object;\r\n\r\n\u00a0 \u00a0 mainPageViewModel =\u00a0new\u00a0MainPageViewModel();\r\n\r\n\u00a0 \u00a0 page.bindingContext =\u00a0mainPageViewModel;\r\n\r\n}\r\n\r\nexport\u00a0function\u00a0onTap(){\r\n\r\n\u00a0 \u00a0 userSettings.username =\u00a0mainPageViewModel.username;\r\n\r\n\u00a0 \u00a0 mainPageViewModel.set(\"dbusername\",userSettings.username);\r\n\r\n}\r\n\r\n<\/pre>\n<p>What have we done? In the first lines we just imported a bunch \u00a0of stuff, checking the comments to see what the modules do. Next we have:<\/p>\n<pre class=\"lang:default decode:true \">let userSettings =\u00a0UserSettings.getInstance();\r\n\r\n<\/pre>\n<p>This is how we get a hold of our UserSettings class instance.<\/p>\n<p>Moving on, we declared another small class:<\/p>\n<pre class=\"lang:default decode:true \">class\u00a0MainPageViewModel\u00a0extends\u00a0Observable{\r\n\r\n\u00a0 \u00a0 public\u00a0username;\r\n\r\n\u00a0 \u00a0 public\u00a0dbusername\r\n\r\n\u00a0 \u00a0 constructor(){\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 super();\r\n\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.dbusername =\u00a0userSettings.username;\r\n\r\n\u00a0 \u00a0 }\r\n\r\n}\r\n\r\n<\/pre>\n<p>As you can see MainPageViewModel\u00a0extends the Observable\u00a0class. If you\u2019re not familiar with Observables know that they are basically JavaScript objects that trigger a notification if one of the properties change. You can find out more <u><a href=\"https:\/\/docs.nativescript.org\/cookbook\/data\/observable\" target=\"_blank\" rel=\"noopener noreferrer\">here<\/a><\/u>.<\/p>\n<p>Our view model has two properties: username (which we bound to our textfield)\u00a0and dbusername (which we bound to our label). Whenever we create a new instance of our class we assign to\u00a0dbusername\u00a0whatever value is present in our userSettings\u00a0instance, which in turn goes and reads data in our database (remember our get username()\u00a0getter method?).<\/p>\n<pre class=\"lang:default decode:true \">export\u00a0function\u00a0navigatingTo(args:\u00a0EventData)\u00a0{\r\n\r\n\u00a0 \u00a0 let page =\u00a0&lt;Page&gt;args.object;\r\n\r\n\u00a0 \u00a0 mainPageViewModel =\u00a0new\u00a0MainPageViewModel();\r\n\r\n\u00a0 \u00a0 page.bindingContext =\u00a0mainPageViewModel;\r\n\r\n}<\/pre>\n<p>This function gets called everytime we navigate to our page. We instantiate our\u00a0MainPageViewModel\u00a0class and assign it to the mainPageViewModel\u00a0variable and we bind it to our page. Plain and simple.<\/p>\n<p>Last,\u00a0but not least,\u00a0we define the behavior for the button click:<\/p>\n<pre class=\"lang:default decode:true \">export\u00a0function\u00a0onTap(){\r\n\r\n\u00a0 \u00a0 userSettings.username =\u00a0mainPageViewModel.username;\r\n\r\n\u00a0 \u00a0 mainPageViewModel.set(\"dbusername\",userSettings.username);\r\n\r\n}<\/pre>\n<p>Once again,\u00a0very simple: We write to the database whatever value our textfield holds (mainPageViewModel.username is bound to the textfield) and then we go and update the value of dbusername\u00a0in order to update the label. An image is worth a thousand words,\u00a0soooo here comes a GIF!<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-5669 size-full\" src=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/06\/ezgif-2-b128d6c35c-compressor.gif\" alt=\"\" width=\"480\" height=\"768\" \/><\/p>\n<p><a href=\"https:\/\/www.couchbase.com\/community\/community-writers-program\/\"><em>This post is part of the Couchbase Community Writing Program<\/em><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Couchbase is a great tool to persist data inside our app. If you haven\u2019t heard of it, it\u2019s a document object storage that allows you to save your data.<\/p>\n<p>If you are using NativeScript-Angular, there are already some great tutorials on how to get started and some more advanced features. In this article we\u2019ll focus on NativeScript with TypeScript.<\/p>\n","protected":false},"author":53,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1814,1821,1816,1819],"tags":[1589],"ppma_author":[9026],"class_list":["post-3673","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-application-design","category-couchbase-architecture","category-couchbase-server","category-data-modeling","tag-nativescript"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.8 (Yoast SEO v25.8) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Persist and Abstract Data in a Nativescript Typescript Application - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Persist and Abstract Data in a Nativescript Typescript Application\" \/>\n<meta property=\"og:description\" content=\"Couchbase is a great tool to persist data inside our app. If you haven\u2019t heard of it, it\u2019s a document object storage that allows you to save your data.  If you are using NativeScript-Angular, there are already some great tutorials on how to get started and some more advanced features. In this article we\u2019ll focus on NativeScript with TypeScript.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2017-06-05T09:03:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-06-19T09:15:21+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/06\/AaronUllal-300x200.png\" \/>\n<meta name=\"author\" content=\"Laura Czajkowski, Developer Community Manager, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Laura Czajkowski, Developer Community Manager, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\"},\"author\":{\"name\":\"Laura Czajkowski, Developer Community Manager, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5f1a0ece4e644bc8c037686fbc8f3220\"},\"headline\":\"Persist and Abstract Data in a Nativescript Typescript Application\",\"datePublished\":\"2017-06-05T09:03:15+00:00\",\"dateModified\":\"2023-06-19T09:15:21+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\"},\"wordCount\":1443,\"commentCount\":1,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"keywords\":[\"nativescript\"],\"articleSection\":[\"Application Design\",\"Couchbase Architecture\",\"Couchbase Server\",\"Data Modeling\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\",\"name\":\"Persist and Abstract Data in a Nativescript Typescript Application - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2017-06-05T09:03:15+00:00\",\"dateModified\":\"2023-06-19T09:15:21+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Persist and Abstract Data in a Nativescript Typescript Application\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5f1a0ece4e644bc8c037686fbc8f3220\",\"name\":\"Laura Czajkowski, Developer Community Manager, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/9deb07d5daaa00220534c31768bc4409\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bc8eebaf25cbe39bc12fd7b1ef92550becc3953ab877a3f0285a59ec2d30b754?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bc8eebaf25cbe39bc12fd7b1ef92550becc3953ab877a3f0285a59ec2d30b754?s=96&d=mm&r=g\",\"caption\":\"Laura Czajkowski, Developer Community Manager, Couchbase\"},\"description\":\"Laura Czajkowski is the Snr. Developer Community Manager at Couchbase overseeing the community. She\u2019s responsible for our monthly developer newsletter.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/laura-czajkowski\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Persist and Abstract Data in a Nativescript Typescript Application - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/","og_locale":"en_US","og_type":"article","og_title":"Persist and Abstract Data in a Nativescript Typescript Application","og_description":"Couchbase is a great tool to persist data inside our app. If you haven\u2019t heard of it, it\u2019s a document object storage that allows you to save your data.  If you are using NativeScript-Angular, there are already some great tutorials on how to get started and some more advanced features. In this article we\u2019ll focus on NativeScript with TypeScript.","og_url":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/","og_site_name":"The Couchbase Blog","article_published_time":"2017-06-05T09:03:15+00:00","article_modified_time":"2023-06-19T09:15:21+00:00","og_image":[{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2017\/06\/AaronUllal-300x200.png","type":"","width":"","height":""}],"author":"Laura Czajkowski, Developer Community Manager, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Laura Czajkowski, Developer Community Manager, Couchbase","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/"},"author":{"name":"Laura Czajkowski, Developer Community Manager, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5f1a0ece4e644bc8c037686fbc8f3220"},"headline":"Persist and Abstract Data in a Nativescript Typescript Application","datePublished":"2017-06-05T09:03:15+00:00","dateModified":"2023-06-19T09:15:21+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/"},"wordCount":1443,"commentCount":1,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","keywords":["nativescript"],"articleSection":["Application Design","Couchbase Architecture","Couchbase Server","Data Modeling"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/","url":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/","name":"Persist and Abstract Data in a Nativescript Typescript Application - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2017-06-05T09:03:15+00:00","dateModified":"2023-06-19T09:15:21+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/persist-abstract-data-nativescript-typescript-application\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Persist and Abstract Data in a Nativescript Typescript Application"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/5f1a0ece4e644bc8c037686fbc8f3220","name":"Laura Czajkowski, Developer Community Manager, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/9deb07d5daaa00220534c31768bc4409","url":"https:\/\/secure.gravatar.com\/avatar\/bc8eebaf25cbe39bc12fd7b1ef92550becc3953ab877a3f0285a59ec2d30b754?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bc8eebaf25cbe39bc12fd7b1ef92550becc3953ab877a3f0285a59ec2d30b754?s=96&d=mm&r=g","caption":"Laura Czajkowski, Developer Community Manager, Couchbase"},"description":"Laura Czajkowski is the Snr. Developer Community Manager at Couchbase overseeing the community. She\u2019s responsible for our monthly developer newsletter.","url":"https:\/\/www.couchbase.com\/blog\/author\/laura-czajkowski\/"}]}},"authors":[{"term_id":9026,"user_id":53,"is_guest":0,"slug":"laura-czajkowski","display_name":"Laura Czajkowski, Developer Community Manager, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bc8eebaf25cbe39bc12fd7b1ef92550becc3953ab877a3f0285a59ec2d30b754?s=96&d=mm&r=g","author_category":"","last_name":"Czajkowski","first_name":"Laura","job_title":"","user_url":"","description":"Laura Czajkowski is the Snr. Developer Community Manager at Couchbase overseeing the community. She\u2019s responsible for our monthly developer newsletter."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/3673","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/53"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=3673"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/3673\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=3673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=3673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=3673"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=3673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}