Widget Tricks - ods-select

ods-select allows the selection of one or more items from a list of options. This resource present different combination with ods-facet-results or ods-analysis to feed the selection list.

ods-select widget documentation

Basic example, fed by a static list

ods-select accept any kind of source as long as it’s a json array. It can be an array of strings, but also an array of object and ods-select label-modifier and value-modifier can be used to specify which key in the array item to use for, respectively the label and the field value.

<div class="row">
    <div class="col-md-4 col-md-offset-2 col-sm-6 mb" ng-if="true"
         ng-init="names = ['John','George','Harry','Meredith']; selection">
        <h3>
            Simplest mode, with a string array
        </h3>
        <ods-select options="names"
                    selected-values="selection"
                    placeholder="Pick a name"></ods-select>
        <h4>Input:</h4>
        <pre ng-bind="names|json"></pre>
        <h4>Selection:</h4>
        <pre ng-bind="selection|json"></pre>
    </div>
    <div class="col-md-4 col-sm-6 mb" ng-if="true"
         ng-init="
            names = [
                {name:'Mister John',id:'john'},
                {name:'King George',id:'george'},
                {name:'Prince Harry',id:'harry'},
                {name:'Lady Meredith',id:'meredith'}
            ];
            selection">
        <h3>
            Modifiers options with json object array
        </h3>
        <ods-select options="names"
                    selected-values="selection"
                    label-modifier="name"
                    value-modifier="id"
                    placeholder="Pick a name"></ods-select>
        <h4>Input:</h4>
        <pre ng-bind="names|json"></pre>
        <h4>Selection:</h4>
        <pre ng-bind="selection|json"></pre>
    </div>
</div>
/** DO NOT COPY **/
/* the CSS is only for a better reading of the demo */
.mb {
    margin-bottom: 30px;
}
h3 {
    height: 60px;
}
.odswidget-select {
    margin-bottom: 25px;
}

Basic example, with a default selection

Start with a selected value, and let the user select another one.

You can also force the user to always have a selection.

<div class="row">
    <div class="col-md-4 col-md-offset-2 col-sm-6 mb" ng-if="true"
         ng-init="names = ['John','George','Harry','Meredith']; selection">
        <h3>
            Use ng-init to set the selection only once at the start
        </h3>
        <ods-select ng-init="selection = ['John']"
                    options="names"
                    selected-values="selection"
                    placeholder="Pick a name"></ods-select>
        <h4>Input:</h4>
        <pre ng-bind="names|json"></pre>
        <h4>Selection:</h4>
        <pre ng-bind="selection|json"></pre>
    </div>
    <div class="col-md-4 col-sm-6 mb" ng-if="true"
         ng-init="names = ['John','George','Harry','Meredith']; selection">
        <h3>
            If the selection is cleared, reset it to "John"
        </h3>
        {{ selection = (selection.length > 0 ? selection : ['John']); ''}}
        <ods-select options="names"
                    selected-values="selection"
                    placeholder="Pick a name"></ods-select>
        <h4>Input:</h4>
        <pre ng-bind="names|json"></pre>
        <h4>Selection:</h4>
        <pre ng-bind="selection|json"></pre>
    </div>
</div>
/** DO NOT COPY **/
/* the CSS is only for a better reading of the demo */
.mb {
    margin-bottom: 30px;
}
h3 {
    height: 60px;
}
.odswidget-select {
    margin-bottom: 25px;
}

Filter by type, fed by a facet (via ods-facet-results widget)

ods-facet-results enumerates the values (“categories”) of a facet, and exposes it in a variable. this variable can then be the option source of ods-select.

ods-facet-results widget documentation

Note 1: that facets are limited to the first 100 results, it’s then suitable for categories, types, properties that have a small set of distinct values

Note 2: set disjunctive mode to true in the context parameters to keep other values available after a selection

<div class="container">
    <ods-dataset-context context="ushospitals"
                         ushospitals-dataset="us-hospitals"
                         ushospitals-parameters="{'disjunctive.type':true}">
        <div ods-facet-results="typelist"
             ods-facet-results-facet-name="type"
             ods-facet-results-context="ushospitals">
            <h4>
                Type of hospitals
            </h4>
            <ods-select options="typelist"
                        selected-values="ushospitals.parameters['refine.type']"
                        label-modifier="name + ' - ' + (count | number) + ' hospitals'"
                        value-modifier="name"
                        placeholder="Select a type"></ods-select>
            <br/>
            <ods-map context="ushospitals" scroll-wheel-zoom="false" location="4,38.37612,-106.69922"
                     basemap="jawg.streets"></ods-map>
        </div>
    </ods-dataset-context>
</div>

Filter by the results of an analysis (via ods-analysis widget)

  • Select cities by their population
  • Select companies by their capital, number of employees
  • Select regions by their solar power production
  • Select power sources by their production etc…

Computing the average, maximum, sum of a field to sort de list of proposition in ods-select

ods-analysis Code Library resource and it’s documentation.

Note 1: performing an analysis on a field containing huge quantity of distinct values can alter performances of the page (the browser needs to download the long list of possible values, then it displays and manipulates the list into the widget)

Note 2: selecting a value and refining the context will no longer let you choose other values as they will disappear with the selection. (contrary to ods-facets and ods-facet-results that can use the disjunctive mode, ie. multi selection mode). To counter that, we need 2 contexts: 1 to perform the analysis and feed ods-select, 1 to refine and display the chart

<div class="container">
    <ods-dataset-context context="ctxanalysis,ctxrefine"
                         ctxanalysis-dataset="shanghai-world-university-ranking"
                         ctxanalysis-parameters="{'sort':'world_rank'}"
                         ctxrefine-dataset="shanghai-world-university-ranking"
                         ctxrefine-parameters="{'sort':'world_rank'}">
        <div ods-analysis="rankings"
             ods-analysis-context="ctxanalysis"
             ods-analysis-x="university_name"
             ods-analysis-serie-maxscore="MAX(world_rank_int)"
             ods-analysis-sort="-maxscore"
             ods-analysis-max="100">
            <h3>
                Select an university in this TOP 100 list (sorted by it's best ranking overall)
            </h3>
            <ods-select options="rankings.results"
                        selected-values="ctxrefine.parameters['refine.university_name']"
                        label-modifier="x + ', Best ranking: ' + maxscore"
                        value-modifier="x"
                        placeholder="Select an university"></ods-select>

            <div ng-if="!ctxrefine.parameters['refine.university_name'][0]">
                <h4>Select an university to see it's ranking details over years</h4>
            </div>

            <div ng-if="ctxrefine.parameters['refine.university_name'][0]">
                <h4>{{ ctxrefine.parameters['refine.university_name'][0] }} rankings details, over years</h4>
                <ods-chart single-y-axis="true" align-month="true">
                    <ods-chart-query context="ctxrefine" field-x="year" maxpoints="100"
                                     timescale="year">
                        <ods-chart-serie expression-y="pcp" chart-type="column" label-y="PCP score" function-y="AVG" color="#263891"
                                         scientific-display="true">
                        </ods-chart-serie>
                        <ods-chart-serie expression-y="alumni" label-y="Alumni score" chart-type="column" function-y="AVG" color="#19630A"
                                         scientific-display="true">
                        </ods-chart-serie>
                        <ods-chart-serie expression-y="award" label-y="Award score" chart-type="column" function-y="AVG" color="#F7B133"
                                         scientific-display="true">
                        </ods-chart-serie>
                        <ods-chart-serie expression-y="pub" label-y="Pub score" chart-type="column" function-y="AVG" color="#BA0129"
                                         scientific-display="true">
                        </ods-chart-serie>
                        <ods-chart-serie expression-y="ns" label-y="NS score" chart-type="column" function-y="AVG" color="#C0C5CC"
                                         scientific-display="true">
                        </ods-chart-serie>
                        <ods-chart-serie expression-y="hici" label-y="HICI score" chart-type="column" function-y="AVG" color="#000000"
                                         scientific-display="true">
                        </ods-chart-serie>
                    </ods-chart-query>
                </ods-chart>

            </div>

        </div>
    </ods-dataset-context>
</div>
/** DO NOT COPY **/
/* the CSS is only for a better reading of the demo */
.mb {
    margin-bottom: 30px;
}
h3 {
    height: 60px;
}
.odswidget-select {
    margin-bottom: 25px;
}

Last but not least, the good practice for geo filters ! (showcasing ods-results)

Each time it’s available, filter with the ID! and avoid labels or names! Specially for geographical division (City names, States etc…)

This resource showcase ods-results as the source of ods-select but most of all Opendatasoft geo referentials that always propose codes and labels for each division.

ods-results documentation.

IMPORTANT: In the lander context, an optional parameter fields is set to limit the size of the results. It improves DRASTICALLY the performance to avoid manipulating big geo shapes in geo datasets. We STRONGLY advise to keep this parameter and list only the required fields (ie. the “label field” and the “value field” of your ods-select)

<div class="container">
    <ods-dataset-context context="kreis,lander"
                         lander-dataset="georef-germany-land@public"
                         lander-parameters="{'fields':'lan_name,lan_code'}"
                         kreis-dataset="georef-germany-kreis@public">
        <div ods-results="landerlist"
             ods-results-context="lander"
             ods-results-max="500">
            <h3>
                Display the name, refine with the code
            </h3>
            <ods-select options="landerlist"
                        selected-values="kreis.parameters['refine.lan_code']"
                        label-modifier="fields.lan_name"
                        value-modifier="fields.lan_code"
                        placeholder="Select a Lander"></ods-select>
            <h4>
                Selected Lander code (used to refine the map context) : {{ kreis.parameters['refine.lan_code'] }}
            </h4>
            <ods-map no-refit="true" scroll-wheel-zoom="false" basemap="jawg.sunny" location="6,51.32924,10.45403">
                <ods-map-layer-group>
                    <ods-map-layer context="kreis" color="#0086D6" picto="ods-circle"
                                   show-marker="true" display="auto" shape-opacity="0.8" point-opacity="1"
                                   border-color="#FFFFFF" border-opacity="1" border-size="1.5"
                                   border-pattern="solid" size="4" size-min="3" size-max="5"
                                   size-function="linear"></ods-map-layer>
                </ods-map-layer-group>
            </ods-map>
            <ul>
                <li>
                    <a href="https://data.opendatasoft.com/explore/dataset/georef-germany-land%40public/"
                       target="_blank">Germany Lander dataset source</a>
                </li>
                <li>
                    <a href="https://data.opendatasoft.com/explore/dataset/georef-germany-kreis%40public/"
                       target="_blank">Germany Kreis dataset source</a>
                </li>
            </ul>
    </ods-dataset-context>
</div>

Filters as a sentence New

Read a sentence that describes the applied filters in your page by inlining several ods-select.

<div class="ods-selects">
    <p>Show</p>
    <ods-select selected-values="choice"
                options="['objects','things','stuff']"
                placeholder="pick what you want"></ods-select>
    <p>in the</p>
    <ods-select selected-values="place"
                options="['car','home']"
                placeholder="pick a place"></ods-select>
    <p>since</p>
    <ods-select selected-values="month"
                options="['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']"
                placeholder="month"></ods-select>
    <ods-select selected-values="year"
                options="['2018','2019','2020','2021']"
                placeholder="year"></ods-select>
    <p>.</p>
</div>
/***** Inlined SELECT *****/
.ods-selects {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}

.ods-selects > .odswidget-select {
    margin: 3px 6px;
}
.ods-selects > :not(.odswidget-select) {
    margin-top: 0;
    margin-bottom: 0;
}

Simple inlined layout New

ods-select takes all the available width. In order to inline several ods-select on the same line and keep the same strategy, you need to add some CSS. This resource provides the minimum CSS you need to achieve this easily.

For mobile display, to assure a minimum width of your ods-select, it can be convenient to set a min-width, see comments in the CSS code.

<div class="shared-width-ods-selects">
    <ods-select selected-values="choice"
                options="['objects','things','stuff']"
                placeholder="pick what you want"></ods-select>
    <ods-select selected-values="place"
                options="['car','home']"
                placeholder="pick a place"></ods-select>
    <ods-select selected-values="long"
                options="['2018','2019','2020','2021', 'let see how it behaves with small screens.']"
                placeholder="very long content here, even too long for mobile display"></ods-select>
</div>
/***** Share width inlined ods-select *****/
.shared-width-ods-selects {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
}

.shared-width-ods-selects > .odswidget-select {
    margin: 3px 6px;
    flex: 1;
    /*
        To assure a minimum width, set a min-width property here.
     */
    min-width: 200px;
}