Page tree
Skip to end of metadata
Go to start of metadata

What is a JSAPI Property?

A JavaScript API Property is exactly what it sounds like -- a property on your JSAPI object that can be queried or set from JavaScript. This looks just like 

A JSAPI Property definition consists of two or three parts:

  • A getter method on your JSAPI class
    • By convention we usually name these methods get_(property name)
  • (optionally) A setter method on your JSAPI class
    • By convention we usually name these methods set_(property name)
  • A registration for your property in the constructor of your JSAPI class

Creating an empty JSAPI object

Let's create a really really basic JSAPI class. We're going to use FB::JSAPIAuto as our base class, and we strongly recommend that you do the same!

// MyPluginAPI.h
#include "JSAPIAuto.h"

FB_FWD_POINTER
class MyPluginAPI : public FB::JSAPIAuto
{
public:
    MyPluginAPI();
    ~MyPluginAPI() {};
};
// MyPluginAPI.cpp
#include "MyPluginAPI.h"

MyPluginAPI::MyPluginAPI() : FB::JSAPIAuto("MyPluginAPI object") {
}

There! That was easy, wasn't it? If you pass an instance of this class back to the page, it will have two members: valid and ToString. These members are defined and registered by FB::JSAPIAuto, the base class.

Adding a New Property

Adding a Read-only Property

To add a new property to our MyPluginAPI JSAPI interface, first we need to add a getter method to our class. Lets add a read-only status string, shall we?

// MyPluginAPI.h
class MyPluginAPI : public FB::JSAPIAuto
{
public:
    MyPluginAPI();
    ~MyPluginAPI() {};

    std::string get_status();

protected:
    std::string m_status;
};
// MyPluginAPI.cpp

std::string MyPluginAPI::get_status() {
    return m_status;
}

Great! We now have a getter for our property, but we still can't use it from JavaScript. Remember part three of any JSAPI property: Registration. This determines what the name will be from javascript. To register the property, we add a registerProperty call in the constructor:

// MyPluginAPI.cpp

MyPluginAPI::MyPluginAPI() : FB::JSAPIAuto("MyPluginAPI object") {
    registerProperty("status",  make_property(this, &MyPluginAPI::get_status));
}

That's all there is to it! This object now has a read-only property called "status"! If this were your Root JSAPI object, we could then access it from JavaScript like this:

var plugin = document.getElementById("plugin");
alert(plugin.status);

Note that if your read-only property is just getting a value that is set on your JSAPI object, a read-only Attribute may be the better/easier choice.

Adding a read-write property

Obviously, not all properties will be read-only, so we might want to create a property with a setter as well. This is easy! We just need to create two methods on our class – a getter and a setter.

// MyPluginAPI.h
class MyPluginAPI : public FB::JSAPIAuto
{
public:
    MyPluginAPI();
    ~MyPluginAPI() {};

    std::string get_fullName();
    void set_fullName(const std::string& name);

protected:
    std::string m_fullName;
};
// MyPluginAPI.cpp

std::string MyPluginAPI::get_fullName() {
    return m_fullName;
}
void MyPluginAPI::set_fullName(const std::string& name)
{
    m_fullName = name;
}

Then to register it:

// MyPluginAPI.cpp

MyPluginAPI::MyPluginAPI() : FB::JSAPIAuto("MyPluginAPI object") {
    // Note that there is both a getter and a setter passed to make_property!
    registerProperty("status",  make_property(this, &MyPluginAPI::get_fullName, &MyPluginAPI::set_fullName));
}

Strong dynamic typing

Even though we used std::string as the type of our property, we could have just as easily used a double, int, bool, or even FB::JSObjectPtr. As long as the types on the getter and setter agree with each other and are types that are supported by FireBreath, JSAPIAuto will take care of converting the input to the correct type. If the input cannot be converted to the desired type in a property set call a Javascript exception will be fired into the page.

JavaScript methods

If you want a property to contain a JavaScript method (perhaps for use as a callback), you can do that as well. The datatype you need is FB::JSObjectPtr. Note that all JSAPI-derived objects in FireBreath must be used in a boost::shared_ptr; as a convenience, typedefs are provided for each commonly used type with the suffix Ptr appended:

#include "variant_list.h"

void MyPluginAPI::set_callback(const FB::JSObjectPtr& callback) {
    m_callback = callback;
}

FB::JSObjectPtr MyPluginAPI::get_callback() {
    return m_callback;
}

void MyPluginAPI::someOtherMethodThingy() {
    // Do really cool stuff
    if (m_callback) // if not NULL
        m_callback->InvokeAsync("", FB::variant_list_of(a)("Param2")(3));
}

As always, the registerProperty call in the constructor is exactly the same. The most common use-case for this feature is to perform a task that takes a long time on another thread and then call the callback when finished; in that case you would want to save the callback so you have it later when you need it.

JavaScript value objects

If you need to pass a "dictionary" object from Javascript, you can do that by using a std::map (or any other STL dictionary type, such as hash_map, multimap, etc) as your parameter type. The key should be a std::string, but the value can be any type supported by JSAPIAuto.

JavaScript arrays

If you need to pass an array from Javascript, you can do that by using a std::vector (or any other STL list type, such as list, set, etc) as your parameter type. The template type of the container can be any supported JSAPI type

More types

For a complete list of supported types, see Supported JSAPI types

  • No labels