Mutable data is typically expected to be stored on a component's model. Component models in Infusion are altered through the ChangeApplier functionality, which works to:
- coordinate model state between different components
- allow changes to a component's model to be listened for and responded to as though they are events
What kinds of data are suitable for storing on a component model? The advice from the framework explanation of model objects is:
We recommend that all objects stored in the
model
area of a component conform to an even stricter definition - that they are equivalent to their form serialised as JSON. This implies that they consist of only the following types:Array
,Object
,String
,Number
andBoolean
. In addition, the following values forNumber
should not be used -Infinity
,-Infinity
andNaN
. The valueundefined
also can not be safely stored within a model.
If there is a need to store a non-mutable variable, a non-component object or similar on a component, a typical
convention is to place it within the members
option block. We will not
discuss this topic in the context of this tutorial.
Creating Model Components
First, let's store the "Hello, World!" message on the component model rather than having it directly in the invoker's
arguments, and refer to it from the sayHello
invoker using IoC syntax. In the process, we'll change it from a basic
fluid.component
to a fluid.modelComponent
.
fluid.defaults("fluidTutorial.helloWorld", {
gradeNames: ["fluid.modelComponent"],
// Stores a string value with the key 'message'
// on the component model
model: {
message: "Hello, World!"
},
listeners: {
"onCreate.sayHello": "{that}.sayHello"
},
invokers: {
sayHello: {
funcName: "fluidTutorial.helloWorld.consoleHello",
// Refers to the model.message value of
// the component in the invoker argument
args: ["{that}.model.message"]
}
}
});
fluidTutorial.helloWorld.consoleHello = function (message) {
console.log(message);
};
Listening to Model Changes
Second, let's move from using an event listener to say "Hello, World!" to using a model listener. Model listeners are similar conceptually to event listeners, but they respond to changes in a component's model rather than to component events.
A common pattern in Infusion is to listen to changes to a component's model and then take some further action, such as
invoking a function involving the changed model state. We'll implement this below so that the component invokes its
sayHello
function with the message content each time it changes.
fluid.defaults("fluidTutorial.helloWorld", {
gradeNames: ["fluid.modelComponent"],
model: {
message: "Hello, World!"
},
modelListeners: {
// On the left side, configures a
// model listener listening to the
// 'message' value
//
// On the right side, configures the
// listener to call the component's
// 'sayHello' invoker whenever the
// value changes
message: "{that}.sayHello"
},
invokers: {
sayHello: {
funcName: "fluidTutorial.helloWorld.consoleHello",
args: ["{that}.model.message"]
}
}
});
fluidTutorial.helloWorld.consoleHello = function (message) {
console.log(message);
};
Using the Change Applier
From the console we can now use the changeApplier
functionality available to all model components to update the
model's message
. We should see the new message logged to the console each time, because the modelListener
we've
defined will be called each time the message
content changes.
helloWorld.applier.change("message", "Hello, brave new Infusion world!");
// "Hello, brave new Infusion world!"
helloWorld.applier.change("message", "Goodbye! See you again soon.");
// "Goodbye! See you again soon."