Skip to content

Repeated Elements

StefansArya edited this page Jul 25, 2023 · 5 revisions

Any element with sf-each can be binded with the Array, Object, Map, or Set data type on the model.

<my-elem sf-each="key,val in myMap">
    ...
</my-elem>

<!-- You can also force the value from the list as the component model with sf-as-scope -->
<my-elem sf-each="val in myMap" sf-as-scope></my-elem>

For the example for Array data type, if you push or splice the array data, then the related element will also being modified. But it's not supported for direct change like myArr[0] = "new data" so you need to manually call .refresh(). If you're moving the data into a new index/key you should call .refresh().

These function can be called after the model was initialized. You can add .init = function(){...} for using the reactive array manipulation feature.

Refresh the elements

If you have set new item into the array index (myArray[0] = {...}) then you need to refresh the list so it can rebuild the element for the object. The parameter are optional. But if you have use push, splice, shift, ... you don't need to call .refresh.

myArray.refresh(index = 0, length = 1);

Get element related to the item

Get the DOM element of the selected index, the index should be a number.

myArray.getElement(index);

// You can also use the value instead, if it's array of object
myArray.getElement(myArray[0]);

// Or query the elements inside the array
myArray.$el('.class');

Above function can be used for Repeated list with Array or Object data type.

Available function for Array

The function is including default array function push, unshift, pop, shift, splice, reverse, indexOf, etc.

And below are additional function

function arguments description
swap (onIndex, withIndex) Swap 2 array value and the related element without rebuild the element nodes.
move (fromIndex, toIndex[, length]) Move some array value and the related element without rebuild the element nodes.

Additional function for Object only

You will need to use global sf.add and sf.delete.

function arguments description
sf.add (propertyName, value) Insert new property with value
sf.delete (propertyName) Delete property from object

An example of what you can do with a model

sf.model('music.feedback', function(My, root){
    // For listening click event
    My.delete = console.warn;

    My.reviews = [{
        name:"Aliz Feriana",
        date:"7 January",
        rate:4,
        ...
    }];

    // Register event when 'reviews' was modified
    My.on$reviews = {
        remove:function(elem, remove){
            $(elem).animateKey('bounceOutLeft', function(){
                remove(); // Remove the element
            });

            // Avoid element remove before animation finished
            return true;
        },
        update:function(elem){}, // When element are refreshed
        create:function(elem){}, // When new element are created

        // Only when using virtual scroll
        nearFloor:function(){}, // Scroll almost reach the bottom
        nearCeiling:function(){}, // Scroll almost reach the top

        hitFloor:function(){}, // Scroll hit to the bottom
        hitCeiling:function(){}, // Scroll hit to the top
    };
});

Let's assume all of the example below will be put inside element with sf-each attribute.

<div sf-each="x in reviews">
   ...
</div>

Using template inside repeated element

<h5>{{x.name}} - {{x.date}}</h5>

Using template script inside repeated element

<ul class="stars">{{@exec
    for(var i = 1; i <= 5; i++){
        if(i <= x.rate){
            {[ <li class="active"><i class="icon-star"></i></li> ]}
        }
        else{
            {[ <li><i class="icon-star-empty"></i></li> ]}
        }
    }
}}</ul>

Using event listener inside repeated element

It's easy.. You can put @event anywhere as element attribute.
But currently it wouldn't work inside of enveloped template {[ ... ]} 😅.

<a @click="delete" style="cursor:pointer">Delete</a>