Dynamicznie wczytywana lista dwupoziomowa z pliku JSON pobranego z zewnętrznego serwera do aplikacji Phonegap z użyciem wirtualnej listy wygląda następująco.

Jest to fragment aplikacji dla pola Paintball.
Najważniejsza linijka to ta, gdzie deklarujemy listę:

Strona join.html w aplikacji (trzeba ustawić routing):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<div class="page" data-name="join">
  <div class="navbar">
    <div class="navbar-inner sliding">
        <div class="left">
        <a href="#" class="link back" id="backButton">
          <i class="icon icon-back"></i>
          <span class="ios-only">Powrót</span>
        </a>
      </div>
      <div class="title">Wybierz mecz</div>
      <div class="subnavbar">
        <form data-search-container=".virtual-list" data-search-item="li" data-search-in=".item-title" class="searchbar searchbar-init">
          <div class="searchbar-inner">
            <div class="searchbar-input-wrap">
              <input type="search" placeholder="Szukaj"/>
              <i class="searchbar-icon"></i>
              <span class="input-clear-button"></span>
            </div>
            <span class="searchbar-disable-button">Ignoruj</span>
          </div>
        </form>
      </div>
    </div>
  </div>
  <div class="searchbar-backdrop"></div>
  <div class="page-content">
    <div class="list simple-list searchbar-not-found">
      <ul>
          <li>
             <a class="item-link smart-select smart-select-init" data-open-in="sheet">
                <select name="team">
                  <option value="-1" selected>Brak połączenia</option>
                </select>
                <div class="item-content">
                  <div class="item-inner">
                    <div class="item-title">Nie można wczytać listy meczów</div>
                  </div>
                </div>
          </a>
          </li>        
      </ul>
    </div>
    <div class="list virtual-list media-list searchbar-found"></div>
  </div>      
  </div>

Do tego aplikacja w standardowym dla Framework7 pliku app.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Dom7
var $$ = Dom7;

// Framework7 App main instance
var app  = new Framework7({
  root: '#app', // App root element
  id: 'com.fxteam.tournament', // App bundle ID
  name: 'Torunament', // App name
  theme: 'auto', // Automatic theme detection
  // App root data
  data: function () {
    return {
      user: {
        firstName: 'Adam',
        lastName: 'Fulara',
      },
    };
  },
  // App root methods
  methods: {
    helloWorld: function () {
      app.dialog.alert('Hello World!');
    },
  },
  // App routes
  routes: routes,

});

// Init/Create main view
var mainView = app.views.create('.view-main', {
  url: '/'
});

// Login Screen Demo
$$('#my-login-screen .login-button').on('click', function () {
  var username = $$('#my-login-screen [name="username"]').val();
  var password = $$('#my-login-screen [name="password"]').val();

  // Close login screen
  app.loginScreen.close('#my-login-screen');

  // Alert username and password
  app.dialog.alert('Username: ' + username + '<br>Password: ' + password);
});

////////////////////////////////////////////////
var globalData =
    { //FX dane globalne
        matches: null, //dane JSON meczu
        match: null,
        connectedToGame : false,
        listOfMatches: Array(0),
        virtualList: null,
        currentGameId: -1, //id z bazy
        currentGameTeamNo: -1, //0 pierwsza drużyna, 1 druga - z tablicy indeks
        status: ''
    }

//FX:
////////////////////////////////////////////////////////////////////////////
// JOIN Page
$$(document).on('page:init', '.page[data-name="join"]', function (e) {
    app.preloader.show();
    if (globalData.virtualList) //jeśli lista była już raz inicjowana trzeba ją wyczyścić
        {
            app.virtualList.destroy(globalData.virtualList);
            globalData.listOfMatches = []; //czyścimy tablicę do ponownego wczytania JSON
        }
       // app.preloader.show();

        app.request.json('http://asg.fulara.com/model/match_list.php', function(data)
        {
            app.preloader.hide();
            globalData.matches = data;
            for(var i=0; i<globalData.matches.length; i++)
                { //tworzenie virtual List Framework7 - listy meczy
                    globalData.listOfMatches.push({
                        title: globalData.matches[i]["name"],
                        subtitle: globalData.matches[i]["startTime"],
                        teamA: globalData.matches[i]["teams"][0]["teamName"], //na razie tylko 2 drużyny tu: 0, 1
                        teamB: globalData.matches[i]["teams"][1]["teamName"],
                        matchId: globalData.matches[i]["matchId"]
                       
                    });
                }
                globalData.virtualList = app.virtualList.create({ //tworzenie wirtualnej listy meczy
                    el: '.virtual-list',
                    items: globalData.listOfMatches,
                    searchAll: function (query, items) {
                        var found = [];
                        for (var i = 0; i < items.length; i++) {
                          if (items[i].title.toLowerCase().indexOf(query.toLowerCase()) >= 0 || query.trim() === '') found.push(i);
                        }
                        return found; //return array with mathced indexes
                      },
                      // List item Template7 template
                      itemTemplate:
                        '<li>' +
                          '<a href="#" class="item-link item-content">' +
                            '<select id="{{matchId}}" name="team">'+
                                '<option value="null" selected disabled hidden> Wybierz drużynę</option>'+
                                '<option value="0">{{teamA}}</option>'+
                                '<option value="1">{{teamB}}</option>'+
                            '</select>'+
                            '<div class="item-content">'+
                                '<div class="item-inner">' +
                                    '<div class="item-title-row">' +
                                        '<div class="item-title">{{title}}</div>' +
                                    '</div>' +
                                    '<div class="item-subtitle">{{subtitle}}</div>' +
                                '</div>' +
                             '</div>' +
                          '</a>' +
                        '</li>',
                      // Item height
                      height: app.theme === 'ios' ? 63 : 73,
                }); //end create virtual list
           
               
           function searchArrayIndex(selectedId)
            {//na podstawie Id pola z bazy danych zwraca indeks z tablicy globalData matches o tym ID
                for (var i=0; i<globalData.matches.length; i++)
                    if (globalData.matches[i].matchId == selectedId)
                        return i;
                return 0;
            }
           
           $$("select").change( function(event) {
                  //Wybranie meczu w listy, powrót do głównej storny
                var selectId=event.target.id; //Pobranie ID selecta (jest kilka na stornie)
                var selectedTeam = document.getElementById(selectId).value; //pobranie z selecta wybranej drużyny
                 $$("#match").removeClass("disabled"); //uaktywnienie przycisku meczowego
                 $$("#join").addClass("disabled");
                 var idInArray = searchArrayIndex(selectId);
                 var statusColor = globalData.matches[idInArray]["teams"][selectedTeam]["teamFlag"];
                 globalData.status='<DIV style="color: ' + statusColor + '">W grze: ' + globalData.matches[idInArray]["name"] +
                     ": " + globalData.matches[idInArray]["teams"][selectedTeam]["teamName"] + '</DIV>';
                 document.getElementById("statusInfo").innerHTML = globalData.status;
                 globalData.connectedToGame = true; //jesteśmy w grze, zapamiętaj
                 globalData.currentGameId = selectId;
                 globalData.currentDameTeamNo = selectedTeam;
                 $$("#backButton").click(); //powrót do głównej strony
                });
        }); //end of JSON load
     
});//end init page 'join' function;

//////////////////////////////
// MATCH Page: - przykładowa inna strona - niepotrzebna w tym przykładzie
$$(document).on('page:init', '.page[data-name="match"]', function (e) {
  document.getElementById("matchDescription").innerHTML = globalData.status;
 
  $$("#leave").on('click',function() {
                //Opuszczenie meczu
                   $$("#match").addClass("disabled"); //uaktywnienie przycisku
                    $$("#join").removeClass("disabled");
                    document.getElementById("statusInfo").innerHTML="Niepołączony"; //pasek statusowy
                    document.getElementById("statusInfo").style.color = 'black';
                    globalData.connectedToGame = false;
                    globalData.match = null;
                    $$("#matchBackButton").click();
                });
            });

A po stronie serwera pobieranie pliku JSON (w pliku connect.php oprócz połączenia ustawiamy UTF8 – wymagane przy JSON):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
        include "connection.php"; //wzór pliku we wpisie "Pełny panel administracyjny MySQLi"
        if ($sql = $baza->prepare( "
            SELECT tournament_match.id, tournament_field.name, start_time, end_time, id_field
            FROM tournament_match
            INNER JOIN tournament_field ON tournament_match.id_field = tournament_field.id"
))
        {
                $sql->execute(); //wykonaj SQL
                $sql->bind_result($matchId, $name, $startTime,$endTime, $idField);
                while ($sql->fetch())
                  $listOfMatches[] = array(
                     "matchId" => $matchId,
                     "name" => $name,
                     "startTime" => $startTime,
                     "endTime" => $endTime,
                     "idField" => $idField
                   ); //dla każdego nazwiska tworzy 2 pary, nazwiska przekonwertowane do UTF
                $sql->close();
        }
        foreach ($listOfMatches as &$match) //dla każdego meczu wczytaj drużyny, które są do tego meczu zapisane
        {
            $sql = $baza->prepare( "
                SELECT name, description, points, flag
                FROM tournament_team
                WHERE match_id = ?"
); //wczytuje po kolei wszystkie drużyny związane z meczem (pewno są dwie, ale można więcej)
            $sql->bind_param( "i", $match["matchId"]);
            $sql->execute();
            $sql->bind_result($teamName, $teamDescription, $teamPoints, $teamFlag);
            $id_druzyny = 0; //indeks w tablicy drużyn do meczu
            while ($sql->fetch())
            {
                $matchTeam = array(
                    "teamName" => $teamName,
                    "teamDescription" => $teamDescription,
                    "teamPoints" => $teamPoints,
                    "teamFlag" => $teamFlag
                );
                $match["teams"][$id_druzyny++] = $matchTeam; //kolejna drużyna
            }
            $sql->close();
        }
        $baza->close();
        echo json_encode($listOfMatches, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
?>

Lista jest dwupoziomowa – to znaczy mamy pola meczowe, z których każde ma zadeklarowane drużyny (w tej wersji – dwie)