-
Notifications
You must be signed in to change notification settings - Fork 0
Binding
or Materialization
Sirius has the support of the next types of binding:
- Model to View
- View to Model
- View to View
- View to Function
- Model to Function
Sirius provides a DSL for creating a binding between two sides. Let's check each of them:
We want to reflect changes in a Model to some View. Usually, after a response from our server, we want to do that. Of course, sometimes values of our request to a server are not valid, and in this case, we want to return validation errors also.
class MyModel extends Sirius.BaseModel
@attrs: ["name"]
@validate:
name:
length: min: 3, max: 10
and our HTML-document
<div id="model2view">
<div class="model-name"></div>
<div class="model-errors"></div>
</div>
Okay with it
after that we should define our flow: how to map attributes in the Model to the View? For that goal, Sirius
has the Materializer class, which describes all types of transformations:
Sirius.Materializer.build(model, view)
.field((b) -> b.name) # I can pass function with object which describes all attributes + all validators
.to((v) -> v.zoom(".model-name")) # pass function or pass directly selector as: '.model-name' or a View: new Sirius.View(".model-name")
.field((b) -> b.errors.name.length) # errors from validation
.to((v) -> v.zoom(".model-errors"))
.transform((x) -> "errors are: #{x}") # transform value as you want
.run() # run transformation
after that, if we enter some not valid values like "12" we will get: errors are: Required length in range [0..Infinity], given: 2". or valid value will be reflected if we put a correct name.
Do you ask yourself what should I do if a model has a lot of validators?
That's easy:
.field((b) -> b.errors.name.all) # all validators for the attribute
.field((b) -> b.errors.all) # all validators for the model
if you want to change any attribute of a view
, add class, to change data-*
attribute, etc... use the attribute
method:
.field((b) -> b.name)
.to('div')
.attribute('class')
...
.handle((zoomed_view, transformed_value) -> zoomed_view.render(transformed_value).append('class')) # add new value to the class attribute
Common flow: from input-form to a model, and then from the model to our server, right?
Our model is still the same.
<div id="view2model">
<input name="model-name" />
</div>
and a materialization:
Sirius.Materializer.build(view, model)
.field((v) -> v.zoom("input[name='model-name']")) # from html-input
.to((b) -> b.name) # to attribute name
.transform((changes) -> changes.text) # changes contain element, attribute, and changes see docs
.run()
if I put value to the input, I will see in logs something like that:
DEBUG [MyModel]: [MyModel] set: 'asd' to 'name'
I made the materialization for the attribute, the same flow is possible for a validation.
<div id="view2view-source">
<input name="model-name" />
</div>
<div id="view2view-mirror">
<div class="mirror"></div>
</div>
and the materialization process:
Sirius.Materializer.build(view1, view2)
.field((v) -> v.zoom("input[name='model-name']")) # from the input
.to((v) -> v.zoom('.mirror')) # to the div.mirror
.transform((changes) -> changes.text) # from all changes we need only text-property
.handle((zoomed_view, transformed) ->
zoomed_view.render(transformed).swap()) # zoomed_view = .mirror, tranformed is our text
.run()
<div id="view2function">
<input name="model-name" />
</div>
Sirius.Materializer.build(view)
.field((v) -> v.zoom("input[name='model-name']"))
.to((changes) -> console.log(changes.text)) # just for printing
.run()
Sirius.Materializer.build(model)
.field((b) -> b.name)
.to((value) -> console.log("=====> #{value}"))
.field((b) -> b.errors.all)
.to((value) -> console.log("=====> error: #{value}"))
.run()
if we change the name of our model, we will see in the console:
INFO [LengthValidator]: LengthValidator: start validate 'asd123'
DEBUG [MyModel]: Validate: 'MyModel.name = asd123' with 'length' validator, valid?: 'true'
=====> error: Required length in range [0..Infinity], given: 2
or
DEBUG [MyModel]: [MyModel] set: 'asd123' to 'name'
=====> asd123
We have three options of changes: from the text (like in textarea, input), from checked/selected, or from changes in attributes of an element. Sirius has supported in a materialization:
# text:
{text, from, target}
{text, attribute, from, target}
{state, from, target}
state
is always boolean value
attribute
is an attribute of an element, like class/data, etc...
text
is a new value (texted)
from
is a zoomed view
target
is an original event (click, input, select, checked, and so on)
All of them are available inside transform
or handle
methods.