Skip to content
StefansArya edited this page Jan 7, 2021 · 5 revisions

Initialize/Define Model

// state   : use this to store your model data and make it reactive or exportable
// require : use this to require/get other model/component stores in current namespace
sf.model('something', function(state, require){
    state.text = 'My Name';

    // Run something after this model was loaded on the DOM
    state.init = function(){
        // state.$el('.selector');
    }
});

You can customise the state with other name like My or Store to make easy to write or make it more readable for you.

Let's start with this simple element in the document body.
The mustache template will always synced with the model's state.text.

<sf-m name="something">
    <span>{{ text }}</span>
    Above will turn into below after the script is running.
<!-- <span>My Name</span> -->
</sf-m>

If you're confused, you can try the SharedModel, or Binding example and do some experiment.

Note:

  • Shared Model: All sf-m element with same name will use existing model and sync it's value on each sf-m element.
  • If you don't want to use shared model, the sf.component is your choice
  • The framework will not dive/parse into any custom element (element tag with-dashes), you should add sf-parse to the element attribute if you want it become part of current scope.
<sf-m>
   <div>
      <custom-element sf-parse>
          {{ parseMe }}
      </custom-element>
   </div>
</sf-m>

Element collection

After any element with <sf-m> tag was inserted into DOM, the model will have $el property that contains collection of <sf-m> elements. Component also have $el property, it will always have one value if not being used as empty shell or shared with other component.

<sf-m name="test">
    <div>{{ first }}</div> | <div>{{ second }}</div>
</sf-m>

<sf-m name="test">
    <div>{{ second }}</div> | <div>{{ first }}</div>
</sf-m>
sf.model('test', function(My){
    My.first = "first";
    My.second = "second";

    // This will be called everytime new sf-m element is created
    My.init = function(){
        // Count of sf-m element
        My.$el.length === 2;

        // Count of div element
        My.$el('div').length === 4;
    }
});

Enveloped template

Enveloped template can only be used for special mustache with @ symbol, like {{@exec ... }} or {{@if ... }}.
It's supposed to be used for defining safe HTML template inside an dynamic template.
The enveloped template would looks like {[ <div>HTML here, and also the {{ model.data }} too</div> ]}

Conditional template

Make sure you write JS in the HTML template with ES5 because browser doesn't use transpiler.

sf.model('...', function(My){
    My.view = undefined;

    My.do = {stuff:function(){/* called, but do nothing for now */}};
    My.finished = function(){
        console.log("You will see I will be called :)");
    }
});

Make sure you write JS in the HTML template with ES5 because older browser may not support some ES6 feature. Because view is undefined, below will run do.stuff, finished, and output enveloped template.

<div>
{{@if view === true :
    {[ <div>I'm not visible</div> ]}

  @elseif view === undefined:
    do.stuff();
    finished(true);
    {[ <b>I'm visible!!</b> ]}

  @else:
    {[ <div>I'm not visible</div> ]}
}}
</div>

Executable template

This feature can be a replacement of <script> tag, and can access your model properties directly. This feature also available for sf-repeat-list, and will be able to obtain key or value of the array.

For the example let's start with simple usage like:

  • Creating elements with for loop
  • Call alert
  • Create <br> element
  • And output HTML without escaping
sf.model('something', function(state, require){
    state.number = [1, 2, 3, 4, 5];
});

Make sure you write JS in the HTML template with ES5 because older browser may not support some ES6 feature.

<sf-m name="something">
    <span>
    {{@exec
        for(var i = 0; i < 5; i++){
            {[ <label>i -> {{ i }}</label> ]}
        }

        myAlert("hello");
        {[ <br> ]}

        // Below will displaying the data without escaping the html
        // Always make sure you have secured the output
        // And maybe escaping HTML tags before returning
        return '<b>' + number.join(',') + '</b>';
    }}
    </span>
</sf-m>

And the HTML output content will be escaped like below

<sf-m name="something">
    <span>
        <label>i -&gt; 0</label>
        <label>i -&gt; 1</label>
        <label>i -&gt; 2</label>
        <label>i -&gt; 3</label>
        <label>i -&gt; 4</label>
        <br>
        <b>1,2,3,4,5</b>
    </span>
</sf-m>
Clone this wiki locally