Avg. Rating 5.0

Problem

You want to easily persist a set of settings in your application.

Solution

The easiest way to accomplish this is to work with a file embedded database: Read the settings from the database when the application loads and save them just before it closes.

Detailed explanation

There are many settings you might implement in your application and want to persist--the position of all its windows, the color scheme the users might choose, the name of the default user profile; in short, everything you would like to implement.

Look at the settings database, contained in a SQLite 3 file, and a JavaScript static class which helps loading and persisting the setting values.

For the sake of simplicity, we'll use the database file from within the application directory. In the database we'll need a name and a value column. We'll also put a namespace column, just to be able to group easier similar settings. Just in case we'll add also a unique index to be sure we don't have duplicate records.

CREATE TABLE settings (IdSetting INTEGER PRIMARY KEY, name TEXT, namespace TEXT, value TEXT);
CREATE UNIQUE INDEX [UNIQ] ON [settings]([name]  DESC,[namespace]  DESC)

We'll have all the initial settings populated in the database, settings.db:

+--------------------------------------+
| 1 | title  | NULL     | Set. example |
| 2 | x      | position | 79           |
| 3 | y      | position | 305          |
| 4 | width  | size     | 220          |
| 5 | height | size     | 320          |
+--------------------------------------+

In this example, "title" stores the title of the application, "x" and "y" in namespace "position" persist the application's position on the screen, and "width" and "height" in namespace "size" persist the dimensions of the application's window.

In the JavaScript class we'll implement two methods: load and save. The load method will read everything from the database and load it into the class itself. The save method will compare the setting values at load time with the setting values when the method was called and if something was modified, those entries will be updated in the database.

Settings.js

//a "static" class to handle our app settings
var Settings = {
    //some static properties to hold db connection and the inital state
    __db: null,
    __result: null,
   
    //this method will load the settings from the db
    __load: function(dbconn) {
        Settings.__db = dbconn;
       
        //execute simple select * on the settings table
        var stmt = new air.SQLStatement();
            stmt.sqlConnection = dbconn;
            stmt.text = "select IdSetting, name, value, namespace from settings";
            stmt.execute();
       
        var result = stmt.getResult().data;

        //save the settings in the class property __result
        Settings.__result = result;
       
        //cycle trough the db result and make properties into the class itself
        for( var i=0; i<result.length; i++ ){

            //if the property has namespace create one for it
            if (result[i].namespace!=null) {
                //fetch setting property with namespace
                if (!Settings[result[i].namespace]) {
                    Settings[result[i].namespace] = {};
                }
                Settings[result[i].namespace][result[i].name] = result[i].value;
            } else {
                //a plain setting property - create it directly in the class
                Settings[result[i].name] = result[i].value;
            }
        }
        //make sure we don't cause memory leaks
        stmt = null;
        result = null;
    },
   
    //this method will save all changed settings
    __save: function() {
        var stmt = new air.SQLStatement();
            stmt.sqlConnection = Settings.__db;
       
        //walk trough all settings INITALLY loaded from the database
        for (var i = 0; i < Settings.__result.length; i++) {
           
            //check if the current property has namespace
            if (Settings.__result[i].namespace!=null) {
                //check if the initial value is equal to the current value
                if ( Settings[Settings.__result[i].namespace][Settings.__result[i].name] != Settings.__result[i].value ) {
                    //update the db. bound parameters are always better
                    stmt.text = "update settings set value= :value where name= :name and namespace= :namespace";
                    stmt.parameters[":name"] = Settings.__result[i].name;
                    stmt.parameters[":value"] = Settings[Settings.__result[i].namespace][Settings.__result[i].name];
                    stmt.parameters[":namespace"] = Settings.__result[i].namespace;
                    stmt.execute();
                }
            }
             else {
                //check if the initial value is equal to the current value
                if (Settings[Settings.__result[i].name] != Settings.__result[i].value) {
                    //update the db, look for namespace equals NULL
                    stmt.text = "update settings set value= :value where name= :name and namespace IS NULL";
                    stmt.parameters[":name"] = Settings.__result[i].name;
                    stmt.parameters[":value"] = Settings[Settings.__result[i].name];
                    stmt.execute();
                }
               
            }
           
           
        }
        stmt = null;
    }
};


The class method names are prefixed with "__" to keep cleaner the class namespace, because you might want to have setting names "load" or "save" (which would overwrite the methods if they didn't have those prefixes).

When you call the __load method and provide it with valid database connection, you can read and write settings like this:

Settings.namespace.propertyX

For properties which are designated to a namespace, and

Settings.propertyY

which don't have a namespace, you can read and write like this:

Settings.position.x = 100;
var myTitle = Settings.title;


 And to demonstrate better how to use the class here is a simple application that persists its window position on the screen, the window dimensions and the window title.

<html>
<head>
    <script type="text/javascript" src="AIRAliases.js"></script>
    <script type="text/javascript" src="Settings.js"></script>
    <script type="text/javascript">
        var db = null;
        var stmt = null;

        //the settings database in the app directory
        var dbFile = air.File.applicationDirectory.resolvePath("settings.db");
       
        //on application load connect to the db
        function onApplicationLoad() {
            //add handler to save the settings
            window.nativeWindow.addEventListener("closing", onWindowClose);
           
            //open connection to settings.db database
            db = new air.SQLConnection();
            db.addEventListener( air.SQLEvent.OPEN, onDatabaseOpen );
            db.open( dbFile, air.SQLMode.CREATE );       
        }
       
        //read the settings from db
        function onDatabaseOpen(e) {
            Settings.__load(db);
           
            //set x, y and window title
            window.nativeWindow.x = Settings.position.x
            window.nativeWindow.y = Settings.position.y;
            window.nativeWindow.width = Settings.size.width;
            window.nativeWindow.height = Settings.size.height;
            window.nativeWindow.title = Settings.title;
           
            //show the window
            window.nativeWindow.visible = true;
            }
       
        //method to set window's title
        function setTitle() {
            //update window's title
            window.nativeWindow.title = document.getElementById('titleFld').value;

            //update the settings object
            Settings.title = document.getElementById('titleFld').value;
        }
           
        //read the x and y before the window is closed and save them to db
        function onWindowClose() {
            Settings.position.x = window.nativeWindow.x;
            Settings.position.y = window.nativeWindow.y;
            Settings.size.width = window.nativeWindow.width;
            Settings.size.height = window.nativeWindow.height;

            //save the settings
            Settings.__save();
        }
    </script>
    <style>
        body {padding: 10px; color: #ccc; background: #333;}
        input {width:190px;}
    </style>
</head>
<body onload="onApplicationLoad()">
    Change the title of the application:<hr /><br />

    Window title: <br />
        <input type="text" id="titleFld" /><br />
    <input type="button" value="Change window title" onClick="setTitle()" />

    <br /><br />
    Change window position on the screen, resize it and change the title and these settings will be saved for the next time you run the program
</body>
</html>

settings_proj.air.zip
[The example application AIR file]
settings_app_screen1.gif

+
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

Report abuse

Related recipes