RAD.js is a framework that allows to build
mobile applications faster.
Optimized for iOS, Android, and
Windows Phone 8, as well as supporting all
major Web browsers.

View on GitHub Download

OVERVIEW

RAD.js is the solution to the problem of creating apps with multiplatform capabilities and native-like responsiveness, performance, and usability. It is a toolkit created by MobiDev experts for business needs of mobile startups, well-established businesses, and directly for software developers.

PERFECT FOR SOFTWARE DEVELOPERS

All developers know that multiplatform solutions based on JavaScript/PhoneGap are not going to fade in the nearest observable future. These technologies grow popularity among software owners. RAD.js is a working combination of simplicity and fullness. Working and responsive apps can be easily created by junior developers.

PERFECT FOR MOBILE
STARTUPS

Mobile startups are interested in covering several mobile platforms within limited budgets. RAD.js helps fulfill that need efficiently. The recipe is: build one app, adjust it for all required platforms, and roll it out on the market.

PERFECT FOR WELL-ESTABLISHED COMPANIES

Well-established companies might not have software as their core business. But they surely need software that easily integrates with their own systems, covers as many platforms and devices as possible, and is easy to maintain. RAD.js helps deliver such software.

Check out Rad.js in action!

Easy to start

"Hello World", the simplest application. As you can see, it is just an HTML template view that demonstrates the basic structure of the application, which does not contain non-standard approaches or special cases.


<div class="hello">
    <h1>Hello world!</h1>
</div>


RAD.view("view.start_page", RAD.Blanks.View.extend({
    url: 'source/views/start_page.html'
}));


Complicated stuff becomes easier

Here is how we can create a to-do list with the basic notions in a RAD.js application: view, template, model, collection. This example introduces the construction of basic application structure and organization of interrelations.



<div class="top-bar">
  <div class="navigation-bar">
    <h1>Simple Todo List</h1>
  </div>
</div>
<div class="section create-task">
  <h2>Enter task name</h2>
  <form action="#">
    <input  type="text" class="task-name" placeholder="What needs to be done?" />
    <button type="submit">Add Task</button>
  </form>
</div>
<div class="main">
  <form class="todo-list" action="#">
    <h3 data-template="true">Todo List ({{model.length}}):</h3>
    <div class="scroll-view">
      <div class="scroll-view-body">
        <ul data-template="true">
          {{# _.each(model, function(task, index) { }}
          <li class="{{task.done ? 'done' : ''}}">
          <input type="checkbox" 
                 value="{{index}}" {{task.done ? 'checked' : ''}} />
          <label>{{task.name}}</label>
          <button class="remove-task" data-index="{{index}}"></button>
          </li>
          {{# }); }}
        </ul>
      </div>
    </div>
  </form>
</div>


(function() {
    "use strict";
    RAD.view("view.start_page", RAD.Blanks.ScrollableView.extend({
    url: 'source/views/start_page.html',
    events: {
        'submit': 'addToList',
        'change .todo-list': 'updateList',
        'click .remove-task': 'removeFromList'
    },
    model:RAD.model('list'),

    addToList: function(e) {
        e.preventDefault();
        var field = this.el.querySelector('.task-name'),
            taskName = field.value;

        if (taskName) {
            this.model.unshift({name: taskName, done: false});
            field.value = '';
        }
    },
    updateList: function (e) {
        var checkbox = e.target,
            holder = checkbox.parentNode.parentNode,
            isDone = checkbox.checked,
            index = checkbox.value;

        if (holder.classList) {
            holder.classList.toggle('done');
        }
        this.model.at(index).set({done: isDone}, {silent: true, reset: true});
    },
    removeFromList: function(e) {
        var index = e.currentTarget.getAttribute('data-index');

        this.model.remove(this.model.at(index));
    }
}));
})();

Readymade features written for you

Here we integrate a third-party library to build a non-standard user interface from scratch, when several screens are flipped by swipe (via this third-party library).


RAD.view("view.parent_widget", RAD.Blanks.View.extend({
    swipe_content: [
                    "view.inner_first_widget", 
                    "view.inner_second_widget",
                    "view.inner_third_widget"
                   ],

    tagName: 'div',

    render: function () {
        // important !!!
        // you should redefine render method
        // for avoid url & template using
    },

    onEndRender: function () {
        this._firstTimeAttach = true;
    },

    onStartAttach: function () {
        if (this._firstTimeAttach) {
            if (this._pageController) {
                this._pageController.destroy();
            }

            this._firstTimeAttach = false;
            this._pageController = new Pager(this.el, this);
        }
    },

    getPageCount: function () {
        return this.swipe_content.length;
    },

    setPageContent: function (position, rootElement, helper) {
        this.publish('navigation.show', {
            container_id: rootElement,
            content: this.swipe_content[position],
            animation: 'none'
        });
    }
}));


(function () {
    "use strict";
    RAD.view("view.inner_first_widget", 
        RAD.Blanks.ScrollableView.extend({
        url: 'source/views/inner/first_widget/first_widget.html',
        onEndRender: function () {
            var self = this;
            // Refresh iScroll after all images was loaded
            this.$images = this.$el.find('img');
            this.$images.on('load.images', function () {
                self.refreshScroll();
            });
        },
        onEndDetach: function () {
            this.$images.off('load.images');
        }
    }));
});


<div class="top-bar">
    <h1>First Page</h1>
</div>
<div class="main">
    <div class="scroll-view">
        <div class="scroll-view-body">
            <div class="section">
                <div class="section__header">Swipe to left</div>
                <div class="section__content">
                    <img src="source/assets/download.jpg" 
                         class="img" alt="dummy"/>
                    <p>
                        ...
                        content
                        ...
                    </p>
                </div>
            </div>
        </div>
    </div>
</div>


Easy to share data between views

One of the possible ways of data transition between independent views. It can be used when it's necessary to transmit data required for showing a particular view, but it's unknown whether this view has been created or not.



RAD.view("view.start_page", RAD.Blanks.View.extend({
    url: 'source/views/first_page/start_page.html',
    events: {
        'tap ul li': 'open'
    },
    open: function (e) {
        "use strict";
        var options = {
                container_id: '#screen',
                content: "view.second_page"
            };

        options.extras = {data: e.currentTarget.innerHTML};

        this.publish('navigation.show', options);
    }
}));


RAD.view("view.second_page", RAD.Blanks.View.extend({
    url:'source/views/second_page/second_page.html',
    events: {
        'tap #back': 'goBack'
    },
    goBack: function () {
        "use strict";
        var options = {
            container_id: '#screen',
            content: "view.start_page",
            animation: "slide-out"
        };

        this.publish('navigation.show', options);
    },
    onNewExtras: function (extras) {
        "use strict";
        var self = this;
        self.loader.done(function () {
            self.$("#options").html(extras.data);
        });
    },
    onStartAttach: function () {
        "use strict";
        var self = this;
        self.$("#on_new").html(self.extras.data);
    }
}));