---
# System prepended metadata

title: 台中Youbike API練習
tags: [Example]

---

---
tags: Example,
disqus: hackmd
---

# 台中Youbike API練習

目前有一個問題待處理，就是如果有天api裡的物件屬性欄位名稱更改了，我就要到程式碼裡把有用到這個屬性欄位名稱的地方都改成新的屬性欄位名稱，這樣很費力，要一個一個找。

所以我想把call回來的資料，再做一個整理放到我自己的陣列裡，把我想要的屬性值丟到我自定義的屬性欄位名稱，然後整個程式碼都吃這個名稱。

至少可以確保，我整段程式不會因為api回來的屬性欄位名稱不一樣就要去看有沒有哪裡有影響，而是改我那個整理過的陣列即可。

就是說如果有天拿回來的資料的CAddress這個欄位名稱改了，改叫CRoadName好了，只要把CAddress改成CRoadName就收工了。
```javascript=
selfArray.push({
    cName: element.Position,
    cAddress: element.CAddress,
    cArea: element.CArea,
    eName: element.EName,
    eAddress: element.EAddress,
    eArea: element.EArea,
});

// cAddress: element.CAddress, 
// 改成 
// cAddress: element.CRoadName,
```

> 2020/06/05 - 已透過新增selfArray來解決這個問題，以後即使api欄位名稱變更，我只要去改selfArray的欄位值就可以。

## 程式碼
### html
```htmlmixed=
<html>
    <head>
        <title>台中YouBike站點資訊</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="index.css">
    </head>

    <body>
        <div class="page-body">
            <h2 class="title">台中YouBike站點資訊</h2>

            <div class="select-wrap">
                <div class="drop-wrap">
                    <label for="drop-menu">選擇顯示指定行政區:</label>
                    <select name="drop-menu" id="area-wrap" class="drop-select"></select>
                </div>

                <div class="drop-wrap">
                    <label for="drop-lang">選擇顯示語系:</label>
                    <select name="drop-lang" id="lang-wrap" class="drop-select">
                        <option value="zh-tw">中文</option>
                        <option value="en">英文</option>
                    </select>
                </div>
            </div>

            <div class="table-container">
                <table id="table-wrap" class="table-wrap"></table>
            </div>

            <div id="page-wrap" class="page-wrap"></div>

            <div class="button-wrap">
                <div id="button-prev" class="button">上ㄧ頁</div>
                <div id="button-next" class="button">下ㄧ頁</div>
            </div>
        </div>
    </body>

    <script src="jquery-3.5.1.min.js"></script>
    <script src="index.js"></script>
</html>
```

### CSS
```css=
.clearfix:after {
    display: table;
    content: "";
    clear: both;
}

.title {
    color: #F7CE58;
    text-align: center;
}

.table-container {
    margin-bottom: 10px;
    min-height: 555px;
}
.table-wrap {
    margin: 0 auto;
    border-spacing: 5px;
}
thead th {
    border: 1px solid #055D80;
    padding: 8px;
    background: #B8C13A;
    text-align: left;
}
tr {
    height: 50px;
}
tr:nth-child(even) {
    background: #F7CE58;
}
td {
    border: 1px solid #DDD;
    padding: 8px;
    text-align: left;
}

.page-wrap {
    margin-bottom: 15px;
    text-align: center;
}

.button-wrap {
    text-align: center;
    user-select: none;
}
.button {
    display: inline-block;
    border: solid 1px #CCC;
    border-radius: 5px;
    width: 150px;
    height: 50px;
    cursor: pointer;
    text-align: center;
    line-height: 50px;
    transition: all .3s ease;
}
.button:hover {
    border: solid 1px #F7CE58;
    background: #F7CE58;
    color: #FFF;
}

.select-wrap {
    margin: 0 auto;
    width: 100%;
    max-width: 400px;
}
.drop-wrap {
    margin-bottom: 5px;
}
.drop-wrap label {
    color: #B8C13A;
    font-size: 20px;
}
.drop-select {
    border: solid 2px #28C5DB;
    border-radius: 5px;
    width: 150px;
    height: 30px;
    font-size: 20px;
}
.drop-select:focus {
    border-color: #28C5DB;
    outline: none;
}
```

### JS
```javascript=
/* 立即函示 + 閉包 */
(function() {
    function handleOnload(){
        var buttonPrev = document.getElementById('button-prev');
        var buttonNext = document.getElementById('button-next');
        var tableWrap = document.getElementById('table-wrap');
        var areaWrap = document.getElementById('area-wrap');
        var langWrap = document.getElementById('lang-wrap');
        var pageWrap = document.getElementById('page-wrap');
        var structureDom = '';
        var showNumber = 10; /* 欲顯示的筆數 */
        var pageNumber = 0;  /* 目前所在頁數 */
        var lastPageNumber = 0; /* 最後一頁 */
        var responseData = [];
        var renderArray = []; /* 渲染陣列 */
        var areaArray = []; /* 各區陣列 */
        var selfArray = []; /* 自己整理過的陣列 */
        var lang = 'zh-tw';
        
        var apiObject = {
            handlePage: function(now, last) {
                pageWrap.innerHTML = '<span>' + now + '</span>/<span>' + last + '</span>';
            },
            handleLangChange: function() {
                /* 語系下拉選單切換處理 */
                lang = langWrap.value;

                apiObject.handleRender(pageNumber);
            },
            handleAreaChange: function() {
                /* 各區下拉選單切換處理 */
                var selectedArea = areaWrap.value;
                
                renderArray = [];
                pageNumber = 0;

                if (selectedArea === '顯示全區') {
                    renderArray = selfArray;
                } else {
                    selfArray.forEach(function(currentValue, index, arr){
                        if ( currentValue.cArea == selectedArea ) {
                            renderArray.push(arr[index]);
                        }
                    });
                }

                apiObject.handleCountPage(renderArray);

                apiObject.handleRender(pageNumber);
            },
            handleArea: function() {
                /* 建立一個不重複各區的下拉選單 */
                var tmpArray = [];
                var optionList = '';

                tmpArray[0] = '顯示全區';

                renderArray.forEach(ele => {
                    tmpArray.push(ele.cArea);
                });

                areaArray = tmpArray.filter(function(element, index, arr){
                    return arr.indexOf(element) === index;
                });

                areaArray.map(ele => {
                    optionList = optionList + '<option value="' + ele + '">' + ele + '</option>';
                });

                areaWrap.innerHTML = optionList;
            },
            handleBindEvent: function() {
                buttonNext.addEventListener('click', this.handleToNextPage);
                buttonPrev.addEventListener('click', this.handleToPrevPage);
                areaWrap.addEventListener('change', this.handleAreaChange);
                langWrap.addEventListener('change', this.handleLangChange);
            },
            handleToPrevPage: function() {
                /* 切換至上一頁 */
                if (0 < pageNumber) {
                    pageNumber = pageNumber - 1;
                    apiObject.handleRender(pageNumber);
                    apiObject.handlePage(pageNumber + 1, lastPageNumber + 1);
                }
            },
            handleToNextPage: function() {
                /* 切換至下一頁 */
                if (pageNumber < lastPageNumber) {
                    pageNumber = pageNumber + 1;
                    apiObject.handleRender(pageNumber);
                    apiObject.handlePage(pageNumber + 1, lastPageNumber + 1);
                }
            },
            handleTrDom: function(element, lang) {
                /* 依照語系返回結構 */
                var tableTdName = '';
                var tableTdArea = '';
                var tableTdAddress = '';
                var tableTr = '';

                switch (lang) {
                    case ('zh-tw'):
                        tableTdName = '<td>'+ element.cName +'</td>'; 
                        tableTdArea = '<td>'+ element.cArea +'</td>';
                        tableTdAddress = '<td>'+ element.cAddress +'</td>'; 
                        break;
                    case ('en'):
                        tableTdName = '<td>'+ element.eName +'</td>'; 
                        tableTdArea = '<td>'+ element.eArea +'</td>';
                        tableTdAddress = '<td>'+ element.eAddress +'</td>'; 
                        break;
                    default:
                        break;
                }

                tableTr = '<tr>'+ tableTdArea + tableTdName + tableTdAddress + '</tr>';

                return tableTr;
            },
            handleRender: function(pageNumber) {
                /* 處理表格渲染 */
                var head = pageNumber * showNumber;
                var foot = (pageNumber + 1) * showNumber;
                var tHead = lang === 'en' ? '<thead><tr><th>Area</th><th>Name</th><th>Address</th></tr></thead>' : '<thead><tr><th>區</th><th>站名</th><th>地址</th></tr></thead>';

                structureDom = tHead;
                tableWrap.innerHTML = structureDom;

                renderArray.slice(head, foot).map(ele => {

                    var tableTr = this.handleTrDom(ele, lang);

                    structureDom = structureDom + tableTr;
                });

                tableWrap.innerHTML = structureDom;
            },
            handleCountPage: function(data) {
                /* 計算應有頁數 */
                var countPage = parseFloat(data.length / 10).toString().split('.');

                lastPageNumber = countPage[1] ? parseInt(countPage[0]) : parseInt(countPage[0]) - 1;

                this.handlePage(pageNumber + 1, lastPageNumber + 1);
            },
            handleData: function(responseText) {
                /* 當api成功回傳，處理api回傳資料 */
                responseData = JSON.parse(responseText);

                /* 把responseData的資料整理成自己要的陣列格式 */
                responseData.map(element => {
                    selfArray.push({
                        cName: element.Position,
                        cAddress: element.CAddress,
                        cArea: element.CArea,
                        eName: element.EName,
                        eAddress: element.EAddress,
                        eArea: element.EArea,
                    });
                });

                /* 使用jQuery的$.extend做copy array */
                renderArray = $.extend(true, [], selfArray);

                this.handleRender(pageNumber);

                this.handleArea();

                this.handleCountPage(renderArray);
            },
            callApi: function() {
                $.ajax({
                    method: 'GET',
                    url: 'http://e-traffic.taichung.gov.tw/DataAPI/api/YoubikeAllAPI',
                    dataType: 'text'
                })
                .done(function( data ) {
                    apiObject.handleData(data);
                });
            },
            execute: function() {
                this.callApi();
                this.handleBindEvent();
            }
        }

        return apiObject;
    };
    
    var executeOnload = handleOnload();

    executeOnload.execute();
})();
/* 立即函示 + 閉包 */
```

#### API文件位置
[Taichung YoubikeAPI](http://e-traffic.taichung.gov.tw/DataAPI/swagger/ui/index#/YoubikeAPI)

---

###### tags: `Example` `yuobike` `api`