ractivejs / ractive

Next-generation DOM manipulation
http://ractive.js.org
MIT License
5.94k stars 396 forks source link

help: I cannot understand how to show a list of users and have a search filter #3427

Closed zenitogr closed 11 months ago

zenitogr commented 11 months ago

Description:

I am trying to show a list of users and when I input a search term in an input tag I want the list to show only the items that include that search term

I have seen the demos and examples and the dataset example but cant make it work.

I am trying this:

{{#partial users}}
<dataset data="{{users}}" filter="{{user_filter}}" sortby="{{sortby}}" from="{{from}}" to="{{to}}" count="{{count}}">
<div class="tile">
<span><img class="img-circle" src="{{.picture}}" /></span>
<span style="text-transform: capitalize;">{{.first_name}} {{.last_name}}</span>
<span>{{.email}}</span>
</div>
</dataset>

{{/partial}}

if the search input

{{#partial userList}}
<input class="form-control" value="{{user_filter}}" placeholder="Search user..." />
{{>users}}
{{/partial}}

is this declaration corrent?

<script src="ractive-dataset.js"></script>

and the file ractive-dataset.js is:

Ractive.components["dataset"] = Ractive.extend({
    lazy: true,
    isolated: true,
    data: {
        data: [],
        filter: '',
        sortby: '',
        from: 0,
        to: 0,
        count: 1
    },
    computed: {
        rows: function(){
            var indexes = this.get('indexes')

            var from = this.get('from')
            var to = this.get('to')

            if( to <= 0 )
                to = indexes.length

            return indexes.slice(from,to)
        },
        indexes: function() {
            var data = this.get('data')
            var filter = this.get('filter')
            var sortby = this.get('sortby')

            function compare(a,b) {
                if (a > b) {
                    return 1;
                }
                if (a < b) {
                    return -1;
                }
                return 0;
            }

            function findAny(obj, str) {
                str = str.toLowerCase()
                for(var key in obj) {
                    var value = String(obj[key]).toLowerCase()
                    if( value.indexOf(str) >= 0 )
                        return true;
                }
                return false;
            }

            if( !filter && !sortby ) {
                // just get the indexes
                result = data.map( function(val,i) { return i; } )
            }
            else {
                // index it
                var result = data.map( function(val,i) { return {index:i, value:val}; } )
                // filter it
                if( filter )
                    result = result.filter( function(entry) { return findAny(entry.value, filter); } )
                // sort it
                if( sortby ) {
                    var reverse = (sortby.charAt(0) === '-')
                    if( !reverse ) {
                        result = result.sort( function(a,b) { return compare(a.value[sortby], b.value[sortby]); } )
                    }
                    else {
                        sortby = sortby.substr(1)
                        result = result.sort( function(b,a) { return compare(a.value[sortby], b.value[sortby]); } )
                    }
                }
                // we need indexes only
                result = result.map( function(entry){ return entry.index; } );
            }

            this.set('count', result.length)

            return result;
        }
    },
    remove: function( keypath ) {
        var dot = keypath.lastIndexOf(".")
        var index = parseInt( keypath.substring(dot+1) )
        this.splice('data', index, 1)
    },
    template: "{{#each rows}}{{#with data[this]}}{{>content}}{{/with}}{{/each}}"
})

Ractive.components["pager"] = Ractive.extend({
    isolated: true,
    data: {
        page: 1,
        of: 10,
        'class': ''
    },
    template: '<div class="{{class}}">' +
                '{{#if page > 1}}' +
                    ' <a href="#1" on-click="set(\'page\', 1)">&lt;&lt;</a>' +
                    ' <a href="#{{page-1}}" on-click="set(\'page\', page-1)">&lt;</a>' +
                '{{/if}}' +
                ' <input type="number" step="1" min="1" max="1000" value="{{page}}" style="width:50px;" /> / {{of}}' +
                ' <div style="display:inline-block; width:80px;">' +
                '{{#if page < of}}' +
                    ' <a href="#{{page+1}}" on-click="set(\'page\', page+1)">&gt;</a>' +
                    ' <a href="#{{of}}" on-click="set(\'page\', of)">&gt;&gt;</a>' +
                '{{/if}}' +
                '</div>' +
            '</div>',
    onchange: function(data) {
        if( !data.page && !data.perpage )
            return
        var p = data.page || this.get('page')
        var pp = data.perpage || this.get('pp')
        this.set('from', (p - 1) * pp)
        this.set('to', p * pp)
    }
})

Ractive.components["ts"] = Ractive.extend({
    isolated: true,
    data: function(){ return {
        sortby: '',
        target: ''
    }},
    template: '<th on-click="toggle()">{{>content}}<span style="width:10px">' +
        '{{#if .sortby === .target}}&#9660;{{/if}}' +
        '{{#if .sortby === ("-" + .target)}}&#9650;{{/if}}' +
        '</span></th>',
    toggle: function() {
        var sortby = this.get('sortby')
        var target = this.get('target')
        if( !sortby )
            this.set('sortby', target)
        else if( sortby === target )
            this.set('sortby', '-' + target)
        else if( sortby === '-' + target )
            this.set('sortby', '')
        else
            this.set('sortby', target)
    }
})
zenitogr commented 11 months ago

this works: so should I just conditionaly hide the tile div with a style="display:none"?

{{#partial users}}
            {{#each users}}
                <div class="tile">
                    <span><img class="img-circle" src="{{.picture}}" /></span>
                    <span style="text-transform: capitalize;">{{.first_name}} {{.last_name}}</span>
                    <span>{{.email}}</span>
                </div>
            {{/each}}
        {{/partial}}
zenitogr commented 11 months ago

for anyone having the same issue I solved it this way:

{{#partial userList}}
            <a href="#" on-click="@this.set('view', 'list')"><h3>Movies <small>Single page app!</small></h3></a>
            <a href="#" on-click="@this.set('view', 'myProfile')"><h3>My Profile</h3></a>
            <h1>User List</h1>
            <button class="btn btn-success" on-click="@this.addUsers(1)">Add 1 user</button>
            <button class="btn btn-success" on-click="@this.addUsers(100)">Add 100 users</button>
            <button class="btn btn-success" on-click="@this.set('users', [])">Clear</button>
            <input class="form-control" value="{{user_filter}}" placeholder="Search user..." />
            <hr/>
            {{>users}}
        {{/partial}}

        {{#partial users}}
            {{#each users}}
                <div class="tile {{#if (.first_name.search(user_filter)==-1)}}hidediv{{/if}}" >
                    <span><img class="img-circle" src="{{.picture}}" /></span>
                    <span style="text-transform: capitalize;">{{.first_name}} {{.last_name}}</span>
                    <span>{{.email}}</span>
                </div>
            {{/each}}
        {{/partial}}
    ```
    .hidediv {
display:none;

}