MyPage is a personalized page based on your interests.The page is customized to help you to find content that matters you the most.


I'm not curious

Windows 8 Apps - Create objects from a JSON file

Published on 13 January 13
532
0
0
Windows 8 Apps - Create objects from a JSON file

As I have been looking around in Windows Store and checking out what kind of apps exist I saw that there a lot of apps which have their content installed on the machine and are not loading it from the web. So even if you don't have internet access you can fully use the app. I though to write a blog post about loading a file in a Windows 8 app and creating objects from the data stored in the file. I will focus on json data, because it's the most commonly used format.


I will present a very simple project (it will not have any change in the UI), but I will try to present a structural guideline how the data and objects can be logically grouped in a Windows 8 WinJS app.


You can find the sample project on github.


Let's say we have our zoo, and some animals were transferred from another zoo. All the data about the animals is sent via a zoo.json file, which looks like this:

[{ "name" : "King", "age" : 5, "hoursSinceLastFeed" : 3 }, { "name" : "Geeko", "age" : 2, "hoursSinceLastFeed" : 12 }, { "name" : "Nerdy", "age" : 12, "hoursSinceLastFeed" : 1 }, { "name" : "Goocy", "age" : 4, "hoursSinceLastFeed" : 6 }] 

This is the most simple set of information about an animal, Name, Age and the hours passed since the last feeding - probably this is the most important one :). This zoo.json file is which we would like to import. So, what I have done was, created a new WinJS application from the

Blank Template:


Windows 8 Apps - Create objects from a JSON file - Image 1
Create a new Blank WinJS project

The next step was, that I added a new JavaScript file, called Animal.js.

/// <reference path="//Microsoft.WinJS.1.0/js/base.js" /> /// <reference path="//Microsoft.WinJS.1.0/js/ui.js" />  (function () { "use strict"; WinJS.Namespace.define("Zoo", { Animal: WinJS.Class.define( //constructor  function () { this._name = ""; this._age = ""; this._isHungry = false; this._hoursSinceLastFeed = 0; }, //methods  { getName: function () { return this._name; }, setName: function (newValue) { this._name = newValue; }, getAge: function () { return this._age; }, setAge: function (newValue) { this._age = newValue; }, isHungry: function () { return this._isHungry; }, getHoursSinceLastFeed: function () { return this._hoursSinceLastFeed; }, setHoursSinceLastFeed: function (newValue) { this._hoursSinceLastFeed = newValue; //if it has been 4 hours since last feed  //the animal is hungry for sure :)  if (newValue > 4) { this._isHungry = true; } else { this._isHungry = false; } }, }, //static methods  { buildAnimal: function (model) { var newAnimal = new Zoo.Animal(); if (model.hasOwnProperty("name")) { newAnimal.setName(model.name); } if (model.hasOwnProperty("age")) { newAnimal.setAge(model.age); } if (model.hasOwnProperty("hoursSinceLastFeed")) { newAnimal.setHoursSinceLastFeed(model.hoursSinceLastFeed); } //return a Bindable object  return new WinJS.Binding.as(newAnimal); }, loadZoo: function (uri) { //IMPORTANT TO RETURN THE PROMISE  return Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri) .then(function (file) { return Windows.Storage.FileIO.readTextAsync(file) .then(function (textFromFile) { var myParsedJsonData = JSON.parse(textFromFile); //this will store all the new animals transferred to zoo  var zoo = new Array(); if (myParsedJsonData) { myParsedJsonData.forEach(function (newObject) { var newAnimal = Zoo.Animal.buildAnimal(newObject); zoo.push(newAnimal); }); } return zoo; }); }); } })//end WinJS.Class.define  }); })();

In this js file I created the object creation and parsing logic. This is the main file which this blog is about. I started the whole process with declaring a self executing function (if you don't know what are those, here are the first second andthird hints which Google gave back when searching for JavaScript self executing functions). I added the "use strict"line, see my previous blog posts why this should be used.

After that comes the interesting part. I said, I will create a new object, inside the namespace Zoo, and that object contains one property, Animal. The Animal is defined as a WinJS.Class using the WinJS.Class.define() method. As it can be seen in the code, this method takes 3 arguments, the first one is a function, this serves as the constructor for the class. The second and the third parameters are objects. The object defined as the second parameter defines the methods which the newly created Animal objects will have:


Windows 8 Apps - Create objects from a JSON file - Image 2


As you can see, Visual Studio 2012 offers a very good intellisense support for JavaScript code. In the constructor I assigned some members to this(so later I can access them). After the definition of the constructor, I defined the methods which will help me in maintaining data integrity and encapsulation for this javascript object. There are defined get and set methods for each property. The isHungry member is treated separately, this has some logic behind the scenes. I said, that if more than 4 hours passed since the last feeding the animal is hungry. All this "complex" logic is implemented inside the setHoursSinceLastFeed() method.


In the third parameter of the WinJS.Class.define() method I specified 2 static methods:

buildAnimal: function (model) { var newAnimal = new Zoo.Animal(); if (model.hasOwnProperty("name")) { newAnimal.setName(model.name); } if (model.hasOwnProperty("age")) { newAnimal.setAge(model.age); } if (model.hasOwnProperty("hoursSinceLastFeed")) { newAnimal.setHoursSinceLastFeed(model.hoursSinceLastFeed); } //return a Bindable object  return new WinJS.Binding.as(newAnimal); },

The buildAnimal function is a simple one. All it does is, checks the model/data passed in as parameter, creates a new Animal object, tries to set it's values from the model passed to the function and returns a bindable object with the help of WinJS.Binding.as() method.

The loadZoo function contains all the code which this blog post is created for. Here is the code:

loadZoo: function (uri) { //IMPORTANT TO RETURN THE PROMISE  return Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri) .then(function (file) { return Windows.Storage.FileIO.readTextAsync(file) .then(function (textFromFile) { var myParsedJsonData = JSON.parse(textFromFile); //this will store all the new animals transferred to zoo  var zoo = new Array(); if (myParsedJsonData) { myParsedJsonData.forEach(function (newObject) { var newAnimal = Zoo.Animal.buildAnimal(newObject); zoo.push(newAnimal); }); } return zoo; }); }); }


The purpose of this function is, to load the file with the json data and create Animal type objects from it. First thing to notice, the function starts with the return statement, this is important and I'll get back to it. The function receives a URL to the file which contains the data. The lineWindows.Storage.StorageFile.getFileFromApplicationUriAsync() accesses the file asynchronously. The method getFileFromApplicationUriAsync() returns a promise, which is chained with the then() method. The.then() method can have 3 parameters (more specifically functions). The first one should be the one which is called when the async operation is finished. The second function parameter stands in the role of an error handler. It is not mandatory to specify this parameter. If you have multiple .then() methods chained, if an error occurs this is escalated till in one of the then() methods an error handler is passed to.


Another scenario is when the invoke chain ends with a .done(), this can also have an error handler as second parameter. If for some reason the error handler function is not specified at all and an error occurs the Windows 8 app will crash (of course if no other error handling mechanism is added). The third parameter of the then() method serves as a progress indicator, more on this in a future post. The getFileFromApplicationUriAsync() returns a promise, the result (file object) of this promise is passed to the function inside the then() method. This object is then accessed and the method WinJS.Storage.FileIO.readTextAsync() reads all the text from the file. This method on it's own returns another promise, and the text read from the file is passed to the function specified for theonCompleted parameter of the then() method. This text is then parsed with the JSON.parse() method. This creates objects from the text passed to it, we can say, that "deserializes" the data. Afterwards a new array is built for results. For each item returned by the JSON.parse() method a new Animal object is created using the buildAnimal static method.


That was all the "science"! We know have a new, fully functional JavaScript class, which implements the factory design pattern and has the feature to load it's own datatype from files and build up it's own objects.

There remained two things to mention. The first is related to the URL passed to the loadZoo function. The URL has to be created with Windows.Foundation.Uri() method, see the code below:

args.setPromise(WinJS.UI.processAll().then(function() { //build up the URL for the file added to the project  var url = new Windows.Foundation.Uri("ms-appx:///zoo.json"); //this will store the imported data  var myNewAnimals = new Array(); //invoke the static method which loads the file  //and creates Animal objects from json data  //THE METHOD RETURNS A PROMISE!!!  Zoo.Animal.loadZoo(url).done( function (result) { myNewAnimals = result; myNewAnimals.forEach(function (animal) { console.log("Name: " + animal.getName() + ", Age: " + animal.getAge() + ", IsHungry: " + animal.isHungry() + ", Hours since Last feed: " + animal.getHoursSinceLastFeed()); }); }, function (error) { var messDialog = new Windows.UI.Popups.MessageDialog(error); messDialog.showAsync(); }); })); 

The parameter given to the Windows.Foundation.Uri() method is a little strange. I will not go in-depth why this has to be written like this, in a future post I will try to present this also. You can figure out that the last / from thems-appx:///zoo.json points to the root of the local project and zoo.json is the name of the processed file. So if you search for ms-appx:// on the web you'll get a lot of details.


Remember the loadZoo method started with a return statement? That was done like that, because all the operations done were executed asynchronously, so I had to be able to chain my logic to the async operations and had to execute it after all the other async logic was executed. So, when the Zoo.Animal.loadZoo(url) finished it's execution in the done() method I write the processed data to the Visual Studio console and it looks like this:


Windows 8 Apps - Create objects from a JSON file - Image 3

You can do anything with these objects, bind them to controls on UI, serve for contracts (Search or Share) and so on.


Thanks for reading the post, hope you enjoyed it.



--------------------
This article is brought to you by Gergo Bogdan, Software Developer. This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




























Windows 8 Apps - Create objects from a JSON file

As I have been looking around in Windows Store and checking out what kind of apps exist I saw that there a lot of apps which have their content installed on the machine and are not loading it from the web. So even if you don't have internet access you can fully use the app. I though to write a blog post about loading a file in a Windows 8 app and creating objects from the data stored in the file. I will focus on json data, because it's the most commonly used format.

I will present a very simple project (it will not have any change in the UI), but I will try to present a structural guideline how the data and objects can be logically grouped in a Windows 8 WinJS app.

You can find the sample project on github.

Let's say we have our zoo, and some animals were transferred from another zoo. All the data about the animals is sent via a zoo.json file, which looks like this:

[{ "name" : "King", "age" : 5, "hoursSinceLastFeed" : 3 }, { "name" : "Geeko", "age" : 2, "hoursSinceLastFeed" : 12 }, { "name" : "Nerdy", "age" : 12, "hoursSinceLastFeed" : 1 }, { "name" : "Goocy", "age" : 4, "hoursSinceLastFeed" : 6 }] This is the most simple set of information about an animal, Name, Age and the hours passed since the last feeding - probably this is the most important one :). This zoo.json file is which we would like to import. So, what I have done was, created a new WinJS application from the

Blank Template:

Windows 8 Apps - Create objects from a JSON file - Image 1


Create a new Blank WinJS project

The next step was, that I added a new JavaScript file, called Animal.js.

/// /// (function () { "use strict"; WinJS.Namespace.define("Zoo", { Animal: WinJS.Class.define( //constructor function () { this._name = ""; this._age = ""; this._isHungry = false; this._hoursSinceLastFeed = 0; }, //methods { getName: function () { return this._name; }, setName: function (newValue) { this._name = newValue; }, getAge: function () { return this._age; }, setAge: function (newValue) { this._age = newValue; }, isHungry: function () { return this._isHungry; }, getHoursSinceLastFeed: function () { return this._hoursSinceLastFeed; }, setHoursSinceLastFeed: function (newValue) { this._hoursSinceLastFeed = newValue; //if it has been 4 hours since last feed //the animal is hungry for sure :) if (newValue > 4) { this._isHungry = true; } else { this._isHungry = false; } }, }, //static methods { buildAnimal: function (model) { var newAnimal = new Zoo.Animal(); if (model.hasOwnProperty("name")) { newAnimal.setName(model.name); } if (model.hasOwnProperty("age")) { newAnimal.setAge(model.age); } if (model.hasOwnProperty("hoursSinceLastFeed")) { newAnimal.setHoursSinceLastFeed(model.hoursSinceLastFeed); } //return a Bindable object return new WinJS.Binding.as(newAnimal); }, loadZoo: function (uri) { //IMPORTANT TO RETURN THE PROMISE return Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri) .then(function (file) { return Windows.Storage.FileIO.readTextAsync(file) .then(function (textFromFile) { var myParsedJsonData = JSON.parse(textFromFile); //this will store all the new animals transferred to zoo var zoo = new Array(); if (myParsedJsonData) { myParsedJsonData.forEach(function (newObject) { var newAnimal = Zoo.Animal.buildAnimal(newObject); zoo.push(newAnimal); }); } return zoo; }); }); } })//end WinJS.Class.define }); })();In this js file I created the object creation and parsing logic. This is the main file which this blog is about. I started the whole process with declaring a self executing function (if you don't know what are those, here are the first second andthird hints which Google gave back when searching for JavaScript self executing functions). I added the "use strict"line, see my previous blog posts why this should be used.

After that comes the interesting part. I said, I will create a new object, inside the namespace Zoo, and that object contains one property, Animal. The Animal is defined as a WinJS.Class using the WinJS.Class.define() method. As it can be seen in the code, this method takes 3 arguments, the first one is a function, this serves as the constructor for the class. The second and the third parameters are objects. The object defined as the second parameter defines the methods which the newly created Animal objects will have:

Windows 8 Apps - Create objects from a JSON file - Image 2


As you can see, Visual Studio 2012 offers a very good intellisense support for JavaScript code. In the constructor I assigned some members to this(so later I can access them). After the definition of the constructor, I defined the methods which will help me in maintaining data integrity and encapsulation for this javascript object. There are defined get and set methods for each property. The isHungry member is treated separately, this has some logic behind the scenes. I said, that if more than 4 hours passed since the last feeding the animal is hungry. All this "complex" logic is implemented inside the setHoursSinceLastFeed() method.

In the third parameter of the WinJS.Class.define() method I specified 2 static methods:

buildAnimal: function (model) { var newAnimal = new Zoo.Animal(); if (model.hasOwnProperty("name")) { newAnimal.setName(model.name); } if (model.hasOwnProperty("age")) { newAnimal.setAge(model.age); } if (model.hasOwnProperty("hoursSinceLastFeed")) { newAnimal.setHoursSinceLastFeed(model.hoursSinceLastFeed); } //return a Bindable object return new WinJS.Binding.as(newAnimal); },The buildAnimal function is a simple one. All it does is, checks the model/data passed in as parameter, creates a new Animal object, tries to set it's values from the model passed to the function and returns a bindable object with the help of WinJS.Binding.as() method.

The loadZoo function contains all the code which this blog post is created for. Here is the code:

loadZoo: function (uri) { //IMPORTANT TO RETURN THE PROMISE return Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri) .then(function (file) { return Windows.Storage.FileIO.readTextAsync(file) .then(function (textFromFile) { var myParsedJsonData = JSON.parse(textFromFile); //this will store all the new animals transferred to zoo var zoo = new Array(); if (myParsedJsonData) { myParsedJsonData.forEach(function (newObject) { var newAnimal = Zoo.Animal.buildAnimal(newObject); zoo.push(newAnimal); }); } return zoo; }); }); }

The purpose of this function is, to load the file with the json data and create Animal type objects from it. First thing to notice, the function starts with the return statement, this is important and I'll get back to it. The function receives a URL to the file which contains the data. The lineWindows.Storage.StorageFile.getFileFromApplicationUriAsync() accesses the file asynchronously. The method getFileFromApplicationUriAsync() returns a promise, which is chained with the then() method. The.then() method can have 3 parameters (more specifically functions). The first one should be the one which is called when the async operation is finished. The second function parameter stands in the role of an error handler. It is not mandatory to specify this parameter. If you have multiple .then() methods chained, if an error occurs this is escalated till in one of the then() methods an error handler is passed to.

Another scenario is when the invoke chain ends with a .done(), this can also have an error handler as second parameter. If for some reason the error handler function is not specified at all and an error occurs the Windows 8 app will crash (of course if no other error handling mechanism is added). The third parameter of the then() method serves as a progress indicator, more on this in a future post. The getFileFromApplicationUriAsync() returns a promise, the result (file object) of this promise is passed to the function inside the then() method. This object is then accessed and the method WinJS.Storage.FileIO.readTextAsync() reads all the text from the file. This method on it's own returns another promise, and the text read from the file is passed to the function specified for theonCompleted parameter of the then() method. This text is then parsed with the JSON.parse() method. This creates objects from the text passed to it, we can say, that "deserializes" the data. Afterwards a new array is built for results. For each item returned by the JSON.parse() method a new Animal object is created using the buildAnimal static method.

That was all the "science"! We know have a new, fully functional JavaScript class, which implements the factory design pattern and has the feature to load it's own datatype from files and build up it's own objects.

There remained two things to mention. The first is related to the URL passed to the loadZoo function. The URL has to be created with Windows.Foundation.Uri() method, see the code below:

args.setPromise(WinJS.UI.processAll().then(function() { //build up the URL for the file added to the project var url = new Windows.Foundation.Uri("ms-appx:///zoo.json"); //this will store the imported data var myNewAnimals = new Array(); //invoke the static method which loads the file //and creates Animal objects from json data //THE METHOD RETURNS A PROMISE!!! Zoo.Animal.loadZoo(url).done( function (result) { myNewAnimals = result; myNewAnimals.forEach(function (animal) { console.log("Name: " + animal.getName() + ", Age: " + animal.getAge() + ", IsHungry: " + animal.isHungry() + ", Hours since Last feed: " + animal.getHoursSinceLastFeed()); }); }, function (error) { var messDialog = new Windows.UI.Popups.MessageDialog(error); messDialog.showAsync(); }); })); The parameter given to the Windows.Foundation.Uri() method is a little strange. I will not go in-depth why this has to be written like this, in a future post I will try to present this also. You can figure out that the last / from thems-appx:///zoo.json points to the root of the local project and zoo.json is the name of the processed file. So if you search for ms-appx:// on the web you'll get a lot of details.

Remember the loadZoo method started with a return statement? That was done like that, because all the operations done were executed asynchronously, so I had to be able to chain my logic to the async operations and had to execute it after all the other async logic was executed. So, when the Zoo.Animal.loadZoo(url) finished it's execution in the done() method I write the processed data to the Visual Studio console and it looks like this:

Windows 8 Apps - Create objects from a JSON file - Image 3


You can do anything with these objects, bind them to controls on UI, serve for contracts (Search or Share) and so on.

Thanks for reading the post, hope you enjoyed it.

--------------------

This article is brought to you by Gergo Bogdan, Software Developer. This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

This blog is listed under Development & Implementations , Operating Systems and Mobility Community

Post a Comment

Please notify me the replies via email.

Important:
  • We hope the conversations that take place on MyTechLogy.com will be constructive and thought-provoking.
  • To ensure the quality of the discussion, our moderators may review/edit the comments for clarity and relevance.
  • Comments that are promotional, mean-spirited, or off-topic may be deleted per the moderators' judgment.
You may also be interested in
Awards & Accolades for MyTechLogy
Winner of
REDHERRING
Top 100 Asia
Finalist at SiTF Awards 2014 under the category Best Social & Community Product
Finalist at HR Vendor of the Year 2015 Awards under the category Best Learning Management System
Finalist at HR Vendor of the Year 2015 Awards under the category Best Talent Management Software
Hidden Image Url

Back to Top