0

I added two new input (ass1 and ass2) to a form, created the columns in the database, added it to $fillable in the model, and method in Vue file. The challenge is that every other input saves to the database but my new inputs are not stored to the database.

If I input directly to the database, the data will show up for edit/update but will not store. I have checked and checked through the code and can't find any issue, no error message so far.

If you need any other details I will be happy to provide them.

Please help! I'm on a deadline.

P.S. I have very little knowledge of Vuejs, it's a bit confusing.

This is my form.vue content:

<template>
    <div>
        <form @submit.prevent="proceed" @keydown="assessmentForm.errors.clear($event.target.name)">
            <div class="row">
                <div class="col-12 col-sm-6">
                    <div class="form-group">
                        <label for="">{{trans('exam.assessment_name')}}</label>
                        <input class="form-control" type="text" v-model="assessmentForm.name" name="name" :placeholder="trans('exam.assessment_name')">
                        <show-error :form-name="assessmentForm" prop-name="name"></show-error>
                    </div>
                </div>
                <div class="col-12 col-sm-6">
                    <div class="form-group">
                        <label for="">{{trans('exam.assessment_description')}}</label>
                        <input class="form-control" type="text" v-model="assessmentForm.description" name="description" :placeholder="trans('exam.assessment_description')">
                        <show-error :form-name="assessmentForm" prop-name="description"></show-error>
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-12">
                    <h6 class="card-title">{{trans('exam.assessment_type')}}</h6>
                    <template v-for="(detail,index) in assessmentForm.details">
                        <div class="row">
                            <div class="col-12 col-sm-3">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_name')}} 
                                    <button type="button" class="btn btn-xs btn-danger m-l-20" :key="`${index}_delete_detail`" v-confirm="{ok: confirmDeleteDetail(index)}" v-tooltip="trans('general.delete')"><i class="fas fa-times"></i></button></label>
                                    <input class="form-control" type="text" v-model="detail.name" :name="getDetailName(index)" :placeholder="trans('exam.assessment_detail_name')">
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailName(index)"></show-error>
                                </div>
                            </div>
                            <div class="col-12 col-sm-1">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_code')}}</label>
                                    <input class="form-control" type="text" v-model="detail.code" :name="getDetailCode(index)" :placeholder="trans('exam.assessment_detail_code')">
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailCode(index)"></show-error>
                                </div>
                            </div>
                            <div class="col-12 col-sm-2">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_max_mark')}}</label>
                                    <input class="form-control" type="number" v-model="detail.max_mark" :name="getDetailMaxMarkName(index)" :placeholder="trans('exam.assessment_detail_max_mark')">
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailMaxMarkName(index)"></show-error>
                                </div>
                            </div>
                            <!-- <div class="col-12 col-sm-2">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_pass_percentage')}}</label>
                                    <div class="input-group mb-3">
                                        <input class="form-control" type="number" v-model="detail.pass_percentage" :name="getDetailPassPercentageName(index)" :placeholder="trans('exam.assessment_detail_pass_percentage')">
                                        <div class="input-group-append">
                                            <span class="input-group-text" id="basic-addon1">%</span>
                                        </div>
                                    </div>
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailPassPercentageName(index)"></show-error>
                                </div>
                            </div> -->

                            <div class="col-12 col-sm-2">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_ass1')}}</label>
                                    <input class="form-control" type="number" v-model="detail.ass1" :name="getDetailAssessment1(index)" :placeholder="trans('exam.assessment_detail_ass1')">
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailAssessment1(index)"></show-error>
                                </div>
                            </div>
                            <div class="col-12 col-sm-2">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_ass2')}}</label>
                                    <input class="form-control" type="number" v-model="detail.ass2" :name="getDetailAssessment2(index)" :placeholder="trans('exam.assessment_detail_ass2')">
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailAssessment2(index)"></show-error>
                                </div>
                            </div>


                            <div class="col-12 col-sm-4">
                                <div class="form-group">
                                    <label for="">{{trans('exam.assessment_detail_description')}}</label>
                                    <autosize-textarea v-model="detail.description" rows="2" :name="getDetailDescriptionName(index)" :placeholder="trans('resource.assessment_detail_description')"></autosize-textarea>
                                    <show-error :form-name="assessmentForm" :prop-name="getDetailDescriptionName(index)"></show-error>
                                </div>
                            </div>
                        </div>
                    </template>
                    <div class="form-group">
                        <button type="button" @click="addRow" class="btn btn-info btn-sm waves-effect waves-light">{{trans('exam.add_new_assessment_detail')}}</button>
                    </div>
                </div>
            </div>
            <div class="card-footer text-right">
                <router-link to="/configuration/exam/assessment" class="btn btn-danger waves-effect waves-light ">{{trans('general.cancel')}}</router-link>
                <button type="submit" class="btn btn-info waves-effect waves-light">
                    <span v-if="id">{{trans('general.update')}}</span>
                    <span v-else>{{trans('general.save')}}</span>
                </button>
            </div>
        </form>
    </div>
</template>


<script>
    export default {
        components: {},
        data() {
            return {
                assessmentForm: new Form({
                    name: '',
                    description: '',
                    // details: ['name', 'code', 'max_mark', 'ass1', 'ass2', 'description']
                    details: []
                })
            };
        },
        props: ['id'],
        mounted() {
            if(!helper.hasPermission('access-configuration')){
                helper.notAccessibleMsg();
                this.$router.push('/dashboard');
            }

            if(this.id)
                this.get();
            else {
                this.addRow();
            }
        },
        methods: {
            hasPermission(permission){
                return helper.hasPermission(permission);
            },
            addRow(){
                let new_index = this.assessmentForm.details.push({
                    name: '',
                    code: '',
                    max_mark: '',
                    ass1: '',
                    ass2: '',
                    // pass_percentage: '',
                    description: ''
                })
            },
            confirmDeleteDetail(index){
                return dialog => this.deleteDetail(index);
            },
            deleteDetail(index){
                this.assessmentForm.details.splice(index, 1);
            },
            getDetailName(index){
                return index+'_detail_name';
            },
            getDetailCode(index){
                return index+'_detail_code';
            },
            getDetailMaxMarkName(index){
                return index+'_detail_max_mark';
            },
            // getDetailPassPercentageName(index){
            //     return index+'_detail_pass_percentage';
            // },
            getDetailAssessment1(index){
                return index+'_detail_ass1';
            },
            getDetailAssessment2(index){
                return index+'_detail_ass2';
            },
            getDetailDescriptionName(index){
                return index+'_detail_description';
            },
            proceed(){
                if(this.id)
                    this.update();
                else
                    this.store();
            },
            store(){
                let loader = this.$loading.show();
                this.assessmentForm.post('/api/exam/assessment')
                    .then(response => {
                        toastr.success(response.message);
                        this.assessmentForm.details = [];
                        this.addRow();
                        this.$emit('completed');
                        loader.hide();
                    })
                    .catch(error => {
                        loader.hide();
                        helper.showErrorMsg(error);
                    });
            },
            get(){
                let loader = this.$loading.show();
                axios.get('/api/exam/assessment/'+this.id)
                    .then(response => {
                        this.assessmentForm.name = response.name;
                        this.assessmentForm.description = response.description;

                        response.details.forEach(detail => {
                            this.assessmentForm.details.push({
                                name: detail.name,
                                code: detail.code,
                                max_mark: detail.max_mark,
                                ass1: detail.ass1,
                                ass2: detail.ass2,
                                description: detail.description
                                // pass_percentage: detail.pass_percentage,
                            });
                        });

                        loader.hide();
                    })
                    .catch(error => {
                        loader.hide();
                        helper.showErrorMsg(error);
                        this.$router.push('/configuration/exam/assessment');
                    });
            },
            update(){
                let loader = this.$loading.show();
                this.assessmentForm.patch('/api/exam/assessment/'+this.id)
                    .then(response => {
                        toastr.success(response.message);
                        loader.hide();
                        this.$router.push('/configuration/exam/assessment');
                    })
                    .catch(error => {
                        loader.hide();
                        helper.showErrorMsg(error);
                    });
            }
        }
    }
</script>

This is the model (AssessmentDetail.php):

<?php

namespace App\Models\Configuration\Exam;

use Illuminate\Database\Eloquent\Model;
use Spatie\Activitylog\Traits\LogsActivity;

class AssessmentDetail extends Model
{
    use LogsActivity;

    protected $fillable = [
                            'exam_assessment_id',
                            'name',
                            'max_mark',
                            'ass1',
                            'ass2',
                            // 'pass_percentage',
                            'description',
                            'options'
                        ];
    protected $casts = ['options' => 'array'];
    protected $primaryKey = 'id';
    protected $table = 'exam_assessment_details';
    protected static $logName = 'exam_assessment_detail';
    protected static $logFillable = true;
    protected static $logOnlyDirty = true;
    protected static $ignoreChangedAttributes = ['updated_at'];

    public function assessment()
    {
        return $this->belongsTo('App\Models\Configuration\Exam\Assessment', 'exam_assessment_id');
    }

    public function getOption(string $option)
    {
        return array_get($this->options, $option);
    }

    public function scopeFilterById($q, $id)
    {
        if (! $id) {
            return $q;
        }

        return $q->where('id', '=', $id);
    }

    public function scopeFilterByExamAssessmentId($q, $exam_assessment_id)
    {
        if (! $exam_assessment_id) {
            return $q;
        }

        return $q->where('exam_assessment_id', '=', $exam_assessment_id);
    }

    public function scopeFilterByName($q, $name, $s = 0)
    {
        if (! $name) {
            return $q;
        }

        return $s ? $q->where('name', '=', $name) : $q->where('name', 'like', '%'.$name.'%');
    }
}

This is my Controller (AssessmentController)

<?php

namespace App\Http\Controllers\Configuration\Exam;

use Illuminate\Support\Str;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Requests\Configuration\Exam\AssessmentRequest;
use App\Repositories\Configuration\Exam\AssessmentRepository;

class AssessmentController extends Controller
{
    protected $request;
    protected $repo;

    /**
     * Instantiate a new controller instance.
     *
     * @return void
     */
    public function __construct(
        Request $request,
        AssessmentRepository $repo
    ) {
        $this->request = $request;
        $this->repo = $repo;

        $this->middleware('permission:access-configuration');
        $this->middleware('academic.session.set');
    }

    /**
     * Used to get all Exam Assessments
     * @get ("/api/exam/assessment")
     * @return Response
     */
    public function index()
    {
        return $this->ok($this->repo->paginate($this->request->all()));
    }

    /**
     * Used to print all Exam Assessments
     * @post ("/api/exam/assessment/print")
     * @return Response
     */
    public function print()
    {
        $exam_assessments = $this->repo->print(request('filter'));

        return view('print.configuration.exam.assessment', compact('exam_assessments'))->render();
    }

    /**
     * Used to generate pdf all Exam Assessments
     * @post ("/api/exam/assessment/pdf")
     * @return Response
     */
    public function pdf()
    {
        $exam_assessments = $this->repo->print(request('filter'));

        $uuid = Str::uuid();
        $pdf = \PDF::loadView('print.configuration.exam.assessment', compact('exam_assessments'))->save('../storage/app/downloads/'.$uuid.'.pdf');

        return $uuid;
    }

    /**
     * Used to store Exam Assessment
     * @post ("/api/exam/assessment")
     * @param ({
     *      @Parameter("name", type="string", required="true", description="Name of Exam Assessment"),
     *      @Parameter("description", type="text", required="optional", description="Description of Exam Assessment")
     * })
     * @return Response
     */
    public function store(AssessmentRequest $request)
    {
        $exam_assessment = $this->repo->create($this->request->all());
        // dd('$exam_assessment');

        return $this->success(['message' => trans('exam.assessment_added')]);
    }

    /**
     * Used to get Exam Assessment detail
     * @get ("/api/exam/assessment/{id}")
     * @param ({
     *      @Parameter("id", type="integer", required="true", description="Id of Exam Assessment"),
     * })
     * @return Response
     */
    public function show($id)
    {
        return $this->ok($this->repo->findOrFail($id));
    }

    /**
     * Used to update Exam Assessment
     * @patch ("/api/exam/assessment/{id}")
     * @param ({
     *      @Parameter("id", type="integer", required="true", description="Id of Exam Assessment"),
     *      @Parameter("name", type="string", required="true", description="Name of Exam Assessment"),
     *      @Parameter("description", type="text", required="optional", description="Description of Exam Assessment")
     * })
     * @return Response
     */
    public function update($id, AssessmentRequest $request)
    {
        $exam_assessment = $this->repo->findOrFail($id);

        $exam_assessment = $this->repo->update($exam_assessment, $this->request->all());

        return $this->success(['message' => trans('exam.assessment_updated')]);
    }

     /**
     * Used to reorder all Details of assessment
     * @frontend ("/api/exam/assessment/{id}/reorder")
     * @return Response
     */
    public function reorder($id)
    {
        $exam_assessment = $this->repo->findOrFail($id);

        $this->repo->reorder($exam_assessment, $this->request->all());

        return $this->success(['message' => trans('exam.assessment_updated')]);
    }

    /**
     * Used to delete Exam Assessment
     * @delete ("/api/exam/assessment/{id}")
     * @param ({
     *      @Parameter("id", type="integer", required="true", description="Id of Exam Assessment"),
     * })
     * @return Response
     */
    public function destroy($id)
    {
        $exam_assessment = $this->repo->deletable($id);

        $this->repo->delete($exam_assessment);

        return $this->success(['message' => trans('exam.assessment_deleted')]);
    }
}

These are the routes for the Assessment from Api.php

    Route::get('/exam/assessment/{id}', 'Configuration\Exam\AssessmentController@show');
    Route::post('/exam/assessment', 'Configuration\Exam\AssessmentController@store');
    Route::patch('/exam/assessment/{id}', 'Configuration\Exam\AssessmentController@update');
    Route::delete('/exam/assessment/{id}', 'Configuration\Exam\AssessmentController@destroy');

Screenshot of Inspector, note the 80 and 1000 values were manually entered in the database.[1]

Request Payload Screenshot attached

13
  • but you sucessfully pass the inputs to server ? Commented Jan 27, 2020 at 12:08
  • How do I check that? Commented Jan 27, 2020 at 12:13
  • in your store method, return $request->all() Commented Jan 27, 2020 at 12:16
  • I got the same view even after clearing cache Commented Jan 27, 2020 at 12:27
  • Are your fields not named 1_detail_ass1, 2_detail_ass1, etc...? Those are not defined in your $fillable property. Commented Jan 27, 2020 at 13:09

1 Answer 1

1

Thank you all for your comments.

I finally found the solution.

Apparently, in my controller(AssessmentController) my construct method is getting the input from AssessmentRepository (App\Repository).

public function __construct(
        Request $request,
        AssessmentRepository $repo
    ) {
        $this->request = $request;
        $this->repo = $repo;

        $this->middleware('permission:access-configuration');
        $this->middleware('academic.session.set');
    }

Then $repo is called in my store, update, show, reorder and other methods.

I've never seen or used App\Repositories before.

You learn every day!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.