Here is simple CRUD with frontend using VueJs, backend using api with Laravel
Data structure:
– Question 1
+ Answer 1
+ Answer 2
– Question 2
+ Answer 1
+ Answer 2
+ Answer 3
Add file resources/views/question/list.blade.php
@extends('layouts.admin') @section('content') <script> var questionType = {"1" : "Type 1", "2" : "Type 2"}; </script> <h4 class="m-t-0">Question manage</h4> <div class="row"> <div class="col-sm-12"> <div class="card-box"> <div id="app"> <div class="row"> <div class="col-sm-6"></div> <div class="col-sm-6"> <div id="datatable-responsive_filter" class="dataTables_filter"> <a type="button" class="btn btn-primary" v-on:click="addNew">Add</a> <button type="button" v-on:click="bulkDelete" class="btn btn-primary">Delete</button> </div> </div> </div> <table class="table table-hover mails m-0 table-actions-bar"> <thead> <tr> <th> <div class="checkbox checkbox-primary checkbox-single m-r-15"> <input id="action-checkbox" type="checkbox"/> <label for="action-checkbox"></label> </div> </th> <th>Question</th> <th>Type</th> <th>Description</th> <th>Parameter</th> <th></th> </tr> </thead> <tbody> <tr v-if="showAddPopup()"> <td colspan="6"> <form v-on:submit="save" method="post"> <div class="row"> <div class="col-sm-6"> <div class="form-group"> <label for="title">Question title</label> <input id="title" type="text" class="form-control" v-model="currentItem.title" name="title"> </div> <div class="form-group"> <label for="description">Detail</label> <input id="description" type="text" class="form-control" v-model="currentItem.description" name="description"> </div> <div class="form-group"> <label for="notes">notes</label> <input id="notes" type="text" class="form-control" v-model="currentItem.notes" name="notes"> </div> <div class="form-group"> <label for="type">Type</label> <select name="type" id="" class="form-control" v-model="currentItem.type"> <option v-for="t in questionType" :label="t.display" :value="t.value" :key="t.value"></option> </select> </div> </div> <div class="col-sm-6"> <label for="" class="pull-left">Câu trả lời</label> <button v-on:click="addAnswer" class="btn btn-primary pull-right" type="button">New Answer</button> <table class="table table-hover mails m-0"> <tr v-for="(ans,index) in currentItem.answers"> <td> <input type="hidden" v-model="ans.id"> <input type="text" class="form-control" v-model="ans.content" placeholder="Answer content"> </td> <td width="30%"> <input type="number" class="form-control" v-model.number="ans.point" placeholder="Point"> </td> <td width="10%"><button class="btn btn-danger" type="button" v-on:click="deleteAnswer(index)">X</button></td> </tr> </table> </div> </div> <input type="hidden" name="id" v-model="currentItem.id"/> <center> <button type="submit" class="btn btn-primary ">Save</button> <button type="button" v-on:click="closeAddPopup" class="btn btn-danger ">Close</button> </center> </form> </td> </tr> <tr v-for="item in items"> <td> <div class="checkbox checkbox-primary m-r-15"> <input id="checkbox1" type="checkbox"> <label for="checkbox1"></label> </div> </td> <td> <a v-on:click="detail(item.id)">@{{ item.title }}</a> </td> <td>@{{ item.type }}</td> <td>@{{ item.description }}</td> <td>@{{ item.notes }}</td> <td><a v-on:click="deleteItem(item.id)" class="btn btn-primary">Delete</a></td> </tr> </tbody> </table> </div> </div> </div> </div> <script src="{{ asset('js/question.js') }}"></script> @endsection
Create js file /public/js/question.js
const app = new Vue({ el: '#app', data() { return { items: [], loading: true, new: false, edit: false, currentItem: {}, error: false } }, mounted: function() { fetch(url + "admin?controller=Question&task=getItems", { method: 'get' }) .then((response) => { return response.json() }) .then((jsonData) => { this.items = jsonData; }) }, methods: { addNew(){ this.currentItem = { title:'', description: '', notes: '', type: '', id: '', answers: [] }; this.new = true; }, detail(id){ for (i in this.items){ if(this.items[i].id==id){ this.currentItem = this.items[i]; break; } } this.edit= true; }, save(e){ e.preventDefault(); self = this; axios({ method: 'post', url: url+'admin?controller=Question&task=store', data: this.currentItem, responseType: 'json' }) .then(function(response){ if(response.data.status){ if(self.currentItem.id != ''){ //update for (i in self.items){ if(self.items[i].id==id){ self.items[i] = self.currentItem; break; } } }else{ //insert self.items.push(response.data.data); self.edit=false; self.new=false; } }else{ alert(response.data.message); } }) .catch(function(error) { console.log(error); alert('Error'); self.error = 'Error'; }) }, deleteItem(id){ if(confirm('Do you want to delete?')){ fetch(url+'admin?controller=Question&task=destroy&id='+id, { method: 'get' }) .then((response) => { return response.json() }) .then((jsonData) => { console.log(this.items); if(jsonData.status){ for (i in this.items){ if(this.items[i].id==id){ this.items.splice(i, 1); break; } } }else{ alert('delete failed'); } }).catch(function(error){ alert('Delete fail ed'); }) } }, bulkDelete(e){ }, showAddPopup(e){ return this.edit || this.new; }, closeAddPopup(){ this.edit=false; this.new=false; }, addAnswer(){ this.currentItem.answers.push({content: '',point:''}); }, deleteAnswer(index){ this.currentItem.answers.splice(index,1); } } });
Create Controller file \app\Http\Controllers\Admin\QuestionController.php
<?php namespace App\Http\Controllers\Admin; use App\Http\Controllers\Admin\Controller; use App\Question; use App\Answer; use Illuminate\Http\Request; use App\Glossary\QuestionType; class QuestionController extends Controller { protected $type; private $rule = [ // 'name'=>'required|max:30', ]; public function __construct(){ } public function index() { $questionType = (QuestionType::getAll()); return view('admin.question.list', [ 'questionType' => $questionType ]); } public function getItems(){ $filter = isset($_GET['filter'])?$_GET['filter']:array(); $data = array(); $data['filter'] = $filter; $items = Question::getItems($data['filter']); return $items; } public function getAnswers(){ $question_id = request()->input('id'); return Answer::getAnswers($question_id); } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { return view('admin.question.create', [ ]); } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { $data = request()->post(); $data['description'] = strval($data['description']); $data['notes'] = strval($data['notes']); $answers = $data['answers']; if($data['id']){ $result = Question::find($data['id']); $result->update($data); }else{ $result = Question::create($data); } $result->answers = $this->saveAnswers($result->id,$answers); return ['status'=>1,'data'=>$result]; } private function saveAnswers($question_id,$answers){ if(!$question_id) return []; $result = []; $orignal = Answer::getAnswers($question_id); $orignalId = array_map(function($e){return $e->id;},$orignal); $new = array_filter($answers,function($e){return !isset($e['id']);}); $update = array_filter($answers,function($e){return isset($e['id']);}); $updateId = array_map(function($e){return $e['id'];},$update); sort($orignalId); sort($updateId); $deleteId = array_diff($orignalId,$updateId); if(count($deleteId) > 0){ Answer::destroy($deleteId); } if(count($update)){ foreach($update as $data){ $model = Answer::find($data['id']); $model->update($data); $result[] = $model; } } if(count($new)){ foreach($new as $data){ $data['question_id'] = $question_id; $result[] = Answer::create($data); } } return $result; } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { } public function update(Request $request) { } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy(Request $request) { $id = $request->input('id'); $result = Question::destroy($id); return ['status'=>$result]; } }
Create model file \app\Question.php
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Question extends Model { protected $table = 'questions'; protected $primaryKey = 'id'; // protected $fillable = array('title','description','notes','type'); public static function getItems($filter=[]){ $items = Question::all()->toArray(); $ids = array_map(function($e){return $e['id'];},$items); if($ids){ $answers = \App\Answer::whereIn('question_id',$ids)->get()->toArray(); } foreach($items as &$item){ $item['answers'] = array_filter($answers,function($e) use ($item) {return $e['question_id'] == $item['id'];}); } return $items; } public function answers(){ return $this->hasMany('App\Answer','question_id','id')->select(['id','content','point']); } }