Using Knockout to Populate Bootstrap Rows and Spans

后端 未结 3 1007
太阳男子
太阳男子 2021-02-04 19:41

Well essentially I\'m trying to populate a Bootstrap template via Knockout and a JSON object.

Bootstrap scaffolding:

相关标签:
3条回答
  • 2021-02-04 20:06

    I had to solve a very similar problem myself: rendering bootstrap grids with an observable array but with bootstrap v3 and ko v3.0. I'll leave my solution here for future reference.

    I'm using a plain function instead of a computed one, since binding are implemented using them by default (see RP Niemeyer answer here https://stackoverflow.com/a/6712389/323751)

    In my View Model:

    this.partitioned = function (observableArray, count) {
        var rows, partIdx, i, j, arr;
    
        arr = observableArray();
    
        rows = [];
        for (i = 0, partIdx = 0; i < arr.length; i += count, partIdx += 1) {
            rows[partIdx] = [];
            for (j = 0; j < count; j += 1) {
                if (i + j >= arr.length) {
                    break;
                }
                rows[partIdx].push(arr[i + j]);
            }
        }
        return rows;
    };
    

    Template:

    <div data-bind="foreach: partitioned(userProjects, 3)">
      <div class="row"
           data-bind="template: { name: 'projectCell', foreach: $data }"></div>
    </div>
    
    <script id="projectCell" type="text/html">
      <div class="col-md-4" data-bind="text: name"></div>
    </script>
    

    Hope somebody find this useful.

    0 讨论(0)
  • 2021-02-04 20:06

    I´m using bootstrap3 and wanted to have x objects per row, where x is depending on the window size e.g on the col class.

    e.g i have elements with class :

    col-lg-2 col-md-2 col-sm-3 col-xs-4
    

    so

    if xs then a row has 3 items

    if lg then a row has 6 items ...

    I extended the answer of rkhayrov to put it to work

    /* determine the current bootstrap environment */
    function findBootstrapEnvironment() {
        var envs = ['xs', 'sm', 'md', 'lg'];
    
        $el = $('<div>');
        $el.appendTo($('body'));
    
        for (var i = envs.length - 1; i >= 0; i--) {
            var env = envs[i];
    
            $el.addClass('hidden-'+env);
            if ($el.is(':hidden')) {
                $el.remove();
                return env
            }
        };
    }
    
    
    /* determine How many objs per row */
    function determineObjectsPerRow(){
        switch(findBootstrapEnvironment()) {
            case 'xs':
                return 3;
                break;
            case 'sm':
                return 4;
                break;
            case 'md':
                return 6;
                break;
            case 'lg':
                return 6;
                break;
        }
    }
    
    
            var objsPerRow= determineObjectsPerRow();
    
            for (var i = 0; i < apps.length; i += objsPerRow) {
                var row = [];
                for (var j = 0; j < objsPerRow; ++j) {
                    if (apps[i + j]) {
                        row.push(apps[i + j]);
                    }
                }
                result.push(row);
            }
    

    i added a dependency to width and height, which are observables So the functions will be recomputed if window is resized

    var base = {
        AppModel:function (data) {
            var self = this;
            self.data = ko.observable({
                documents:ko.observableArray([]),
                width:ko.observable($(window).width()),
                height:ko.observable($(window).height())
            });
    
            /* calculate rows based on bootstrap environment */
            self.appRows = ko.computed(function() {
                self.data().height();
                self.data().width();
                var apps = self.data().documents();
                var result = [];
                var objsPerRow= determineObjectsPerRow();
    
                for (var i = 0; i < apps.length; i += objsPerRow) {
                    var row = [];
                    for (var j = 0; j < objsPerRow; ++j) {
                        if (apps[i + j]) {
                            row.push(apps[i + j]);
                        }
                    }
                    result.push(row);
                }
                return result;
            }, self); 
    
        },
    };
    

    and the resize handler

    $(window).resize(function(event) {
        vm.data().height($(window).height());
        vm.data().width($(window).width());
    });
    

    it just works like a Charme, the rows are generated nicely for each device-width

    i leave it here if anyone needs to achieve the same

    0 讨论(0)
  • 2021-02-04 20:08

    Make a computed observable which slices apps observable/observable array into arrays of three elements, and then bind some root element to it with foreach binding. Something like this.

    Observable:

    viewModel.appRows = ko.computed(function() {
        var apps = this.Apps();
        var result = [];
        for (var i = 0; i < apps.length; i += 3) {
            var row = [];
            for (var j = 0; j < 3; ++j) {
                if (apps[i + j]) {
                    row.push(apps[i + j]);
                }
            }
            result.push(row);
        }
        return result;
    }, viewModel);
    

    Markup:

    <div class="container" data-bind="foreach: appRows">
        <div class="row-fluid" data-bind="foreach: $data">
            <div class="span4">
                <h1 data-bind="text: title"></h1>
                <p data-bind="text: description"></p>
            </div>
        </div>
    </div>
    
    0 讨论(0)
提交回复
热议问题