Vue.js에서 Selectbox 컴포넌트 만들기

Vue.js에서 입력 폼을 만들 때 사용할 수 있는 Selectbox 컴포넌트를 만드는 방법을 소개하고자 한다.

SelectBox.vue (이름은 자유롭게 정한다) 파일을 하나 만들고 template를 아래와 같이 작성한다.

<template>
    <select
          v-model="this.value"
          class="custom-select"
          v-bind:id="input_id"
          v-on:input="updateValue($event.target.value)"
    >
        <option v-for="(item, index) in items" :value="index">{{ item }}</option>
    </select>
</template>

Vue.js 2.2 버전부터 v-model을 사용하는 컴포넌트는 value props를 가진다. (참고: #) 따라서 별도로 v-bind로 props를 내려줄 필요 없이 하위 컴포넌트에서 this.value라고만 명시해주면 상위 컴포넌트의 value 값을 하위 컴포넌트 값으로 가져올 수 있다.

그리고, v-on:input="updateValue($event.target.value)" 부분은 사용자가 selectbox의 값을 변경할 경우 변경된 값을 상위 컴포넌트로 전송하기 위한 코드이다. 이 코드가 없으면 상위 컴포넌트에 사용자가 변경한 값이 반영되지 않으니 주의하여야 한다.

script는 아래와 같이 작성한다.

<script>
    export default {
        name: "SelectBox",

        data() {
            return {
                //
            };
        },

        props: ['value', 'items', 'input_id'],

        methods: {
            updateValue: function (value) {
                this.$emit('input', value);
            }
        }

    }
</script>

updateValue 메서드는 사용자가 입력한 값을 input 이벤트로 내보내는 역할을 한다.

마지막으로, 컴포넌트를 가져다 쓰는 부분의 코드는 아래와 같다.

<SelectBox
       v-model="preselect_value"
       :items="somethings"
       :input_id="'my_selectbox'"
       @input="value => { preselect_value = value }"
></SelectBox>

 

Vue.js Component Develop

Mutators 사용 시 "laravel Trying to get property 'name' of non-object" 에러 해결법

Laravel Mutators를 이용하여 Relationships 관계에 있는 컬럼의 값을 포함하고자 하는 경우 getAttribute() Magic 메서드로 포함하고자 할 컬럼을 지정해주고 $appends 프로퍼티에 명시하여야 한다.

다음 코드는 Post 모델에 Category 모델의 name 컬럼을 Post 모델의 category_name 프로퍼티로 포함하는 예제이다.

class Post extends Model
{
    protected $appends = [
        'category_name',
    ];

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function getCategoryNameAttribute()
    {
        return $this->category->name;
    }

}

하지만, 중간중간 해당하는 Category 모델이 없는 경우 (카테고리가 삭제 된 경우) "laravel Trying to get property 'name' of non-object" 에러가 발생한다.

당연히 해당 모델이 없기 때문에 $this->category는 null이 되고,  $this->user->name 프로퍼티에 접근할 수 없기 때문에 발생하는 문제이다.

이럴 경우 다음과 같이 null 여부를 체크하면 된다.

public function getCategoryNameAttribute()
{
    return $this->user !== null ? $this->user->name : null;
}

뿐만 아니라, 개발에 있어서 이와 같은 방어적 코딩을 습관화 하는 것이 좋다.

Develop Laravel Mutators Troubleshooting

Laravel에 AdminLTE Template 통합하기

AdminLTE는 무료 오픈소스 대시보드 템플릿이다. 본 포스트에서는 AdminLTE를 Laravel과 통합하는 방법을 설명하고자 한다.

Laravel 프로젝트에서 다음 명령어를 입력하여 AdminLTE 템플릿을 npm으로 설치한다.
(bower로 설치하는 방법도 있지만 Laravel Mix와 연계를 위해 가급적 npm을 사용하는 것이 좋다고 생각한다.)

npm install admin-lte --save-dev

resources/sass 경로에 admin.scss (이름은 자유롭게 한다.) 파일을 하나 생성하고, 코드를 다음과 같이 입력한다.

// Fonts
@import url('https://fonts.googleapis.com/css?family=Nunito');

// Variables
@import 'variables';

// Font awesome
@import '~font-awesome/scss/font-awesome';

// Bootstrap3
@import '~admin-lte/bower_components/bootstrap/dist/css/bootstrap.css';

// Admin LTE
@import '~admin-lte/dist/css/AdminLTE.css';
@import '~admin-lte/dist/css/skins/_all-skins.css';
@import '~admin-lte/bower_components/Ionicons/scss/ionicons';

참고로 AdminLTE 2.x 버전은 Bootstrap 3에 의존성을 가진다. 2018년 12월 기준 현재 Laravel 5.7 버전은 Bootstrap 4 버전을 내장하고 있기 때문에 기존의 app.scss 파일에 있는 Bootstrap 4를 그대로 사용하면 스타일이 깨져 나온다. admin-lte에 내장된 Bootstrap 3를 사용하도록 한다.

resources/js 경로에 admin.js 파일을 하나 생성하고 코드를 다음과 같이 입력한다.

require('admin-lte');
require('admin-lte/bower_components/chart.js');

webpack.min.js 파일은 다음과 같이 수정한다.

mix.js('resources/js/app.js', 'public/js')
    .js('resources/js/admin.js', 'public/js')

    .sass('resources/sass/app.scss', 'public/css')
    .sass('resources/sass/admin.scss', 'public/css')

    .extract([
        'jquery'
    ])

    .autoload({
        jquery: ['$', 'jQuery', 'jquery'],
    })

    .version();

중간에 autoload 메소드에 jquery를 로드하는 부분 없이 그냥 jquery만 vendor에 통합하면 Error가 발생한다.

다음으로, DashboardController를 생성한다.

php artisan make:controller DashboardController

app/Http/Controllers/DashboardController.php를 아래와 같이 편집한다.

class DashboardController extends Controller
{
    public function index()
    {
        return view('dashboard');
    }
}

routes/web.php를 아래와 같이 편집한다.

Route::get('/admin', 'DashboardController@index')->name('dashboard');

resources/views/layouts 에 다음과 같이 레이아웃 파일을 생성한다. 레이아웃 형식은 자유롭게 작성한다.

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- CSRF Token -->
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title></title>

    <link href="{{ asset('css/admin.css') }}" rel="stylesheet">
</head>
<body class="hold-transition skin-blue sidebar-mini">

<div id="app">
    @yield('content')
</div>

<!-- Scripts -->
<script src="{{ mix('js/manifest.js') }}"></script>
<script src="{{ mix('js/vendor.js') }}"></script>
<script src="{{ mix('js/admin.js') }}"></script>
<script src="{{ mix('js/app.js') }}"></script>

@yield('script')
</body>
</html>

이제 resources/views에 dashboard.blade.php 뷰 파일을 생성하고 AdminLTE 데모 페이지의 소스를 참고해 내용을 채워넣는다.

js와 sass파일을 컴파일한다.

npm run prod

 

Develop Laravel AdminLTE