dimanche 24 mai 2020

How to create and update post in Vue and Laravel 5

I want to build a Vue frontend over API data. I can retrieve and delete contents. But i can neither Create nor update content in Vue. I know it's an issue with my Vue script because the API works fine without the frontend. My application is built using Laravel 5.8

The following are my API routes:

//Show a headline
Route::get('Headlines/{id}', 'NewsheadlinesController@show');

//List all headlines
Route::get('Headlines', 'NewsheadlinesController@index');

//Create a headline
Route::post('Headline', 'NewsheadlinesController@store');

//Update a headline
Route::put('Headline', 'NewsheadlinesController@store');

//Delete a headline
Route::delete('Headline/{id}', 'NewsheadlinesController@destroy');

My web.php route:

Route::get('/', function () {
    return view('layouts.headline');
});

Here's my Vue component register:

Vue.component('navbar', require('./components/Navbar.vue').default);
Vue.component('headlines', require('./components/Headlines.vue').default);

Navbar.vue component:

<template>
    <nav class="navbar navbar-expand-sm navbar-dark bg-info mb-2">
        <div class="container">
            <a href="#" class="navbar-brand">News Headlines</a>
        </div>
    </nav>
</template>

Headlines.vue component markup:

<template>
    <div>
        <h2>Headlines</h2>
        <div class="row">
            <div class="col-sm-12 col-md-4 col-lg-4">
                <h3>Create News Headlines</h3>
                <form @submit.prevent="addHeadline">
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Enter Title" v-model="headline.title" required>
                    </div>
                    <div class="form-group">
                        <textarea class="form-control" placeholder="Enter summary" v-model="headline.description" required></textarea>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Unique identification or alias of the curator or correspondent" v-model="headline.identity" required>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Name of the curator or correspondent" v-model="headline.name" required>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Enter URL for this News Headline" v-model="headline.url" required>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Enter URL to photo image" v-model="headline.urlToImage" required>
                    </div>
                    <div class="form-group">
                        <textarea class="form-control" placeholder="Enter full content" v-model="headline.content" required></textarea>
                    </div>
                    <div class="form-group">
                        <select class="form-control" v-model="headline.category" required>
                            <option value="">Select news category</option>
                            <option value="health">Health</option>
                            <option value="science">Science</option>
                            <option value="general">General</option>
                            <option value="technology">Technology</option>
                            <option value="entertainment">Entertainment</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <select class="form-control" v-model="headline.language" required>
                            <option value="">Select your language</option>
                            <option value="nl">Netherlands</option>
                            <option value="ch">Chinese</option>
                            <option value="en">English</option>
                            <option value="fr">French</option>
                            <option value="es">Spanish</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <select class="form-control" v-model="headline.country" required>
                            <option value="">Select you country</option>
                            <option value="ru">Russia</option>
                            <option value="nl">Netherlands</option>
                            <option value="ch">China</option>
                            <option value="uk">United Kingdom</option>
                            <option value="fr">France</option>
                            <option value="us">USA</option>
                            <option value="sp">Spain</option>
                        </select>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Set publication time for this Headline" v-model="headline.publishedAt" required>
                        <small class="form-text text-muted">Year-Month-Day Hour:Minute:Second => 2001-03-07 04:05:20</small>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" disabled="" value="2001-03-07 04:05:20" v-model="headline.created_at" required>
                        <small class="form-text text-muted">Creation time for this Headline => Year-Month-Day Hour:Minute:Second</small>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" disabled="" value="2001-03-07 04:05:20" v-model="headline.updated_at" required>
                        <small class="form-text text-muted">Last editing time for this Headline => Year-Month-Day Hour:Minute:Second</small>
                    </div>
                    <div class="form-group">
                        <input type="text" class="form-control" placeholder="Enter photo caption" v-model="headline.diskImageFileName" required>
                        <small class="form-text text-muted">Maximum is 30 characters</small>
                    </div>
                    <button type="submit" class="btn btn-dark btn-block">Upload</button>
                </form>
            </div>
            <div class="col-sm-12 col-md-8 col-lg-8">
                <nav aria-label="News headline pagination">
                    <ul class="pagination">
                        <li v-bind:class="[{disabled: !pagination.prev_page_url}]" class="page-item">
                            <a class="page-link" href="#" @click="fetchHeadlines(pagination.prev_page_url)">
                                Previous
                            </a>
                        </li>
                        <li class="page-item disabled">
                            <a class="page-link text-dark" href="">
                                Page  of 
                            </a>
                        </li>
                        <li v-bind:class="[{disabled: !pagination.next_page_url}]" class="page-item">
                            <a class="page-link" href="#" @click="fetchHeadlines(pagination.next_page_url)">
                                Next
                            </a>
                        </li>
                    </ul>
                </nav>
                <div class="card card-body mb-2" v-for="headline in headlines" v-bind:key="headline.id">
                    <h3></h3>
                    <div class="row col-offset-md-2 col-md-10 mb-2">
                        <div class="col-sm-12 col-md-8 col-lg-8">
                            <p><b>Category:</b> . <br><b>Created by: </b> <br>
                            <i>Created on . <br>Published on </i><br>
                            <b>Country ISO code:</b> . <b>Language: </b> <br></p>
                            <p>Post ID: </p>
                        </div>
                        <div class="col-sm-12 col-md-4 col-lg-4">
                            <img style="height: 150px; width: 200%; display: block;" src="" alt="">
                        </div>
                    </div>
                    <p><b>Summary:</b>  </p>
                    <p><b>Content:</b>    </p>

                    <button @click="editHeadline(headline)" class="btn btn-warning mb-2">Edit news</button>

                    <button @click="deleteHeadline(headline.id)" class="btn btn-danger">Delete news</button>
                </div>
            </div>
        </div>
    </div>
</template>

Headlines.vue component script:

<script>
    export default {
        data() {
            return {
                headlines: [],
                headline: {
                    id: '',
                    identity: '',
                    name: '',
                    title: '',
                    description: '',
                    url: '',
                    urlToImage: '',
                    publishedAt: '',
                    content: '',
                    category: '',
                    language: '',
                    country: '',
                    diskImageFileName: '',
                    created_at: '',
                    updated_at: ''
                },
                headline_id: '',
                pagination: {},
                edit: false
            };
        },

        created() {
            this.fetchHeadlines();
        },

        methods: {
            fetchHeadlines(page_url){
                let vm = this;
                page_url = page_url || 'api/Headlines';
                fetch(page_url)
                    .then(res => res.json())
                    .then(res => {
                        this.headlines = res.data;
                        vm.makePagination(res.meta, res.links);
                    })
                    .catch(err => console.log(err));
            },/* end fetchHeadlines */

            makePagination(meta, links) {
                let pagination = {
                    current_page: meta.current_page,
                    last_page: meta.last_page,

                    first_page_url: links.first,
                    last_page_url: links.last,

                    next_page_url: links.next,
                    prev_page_url: links.prev
                };

                this.pagination = pagination;
            },/* end makePagination */

            deleteHeadline(id) {
                if(confirm('Deleting a news headline is irreversible. Are you sure you want to delete it?')) {
                    fetch(`api/Headline/${id}`, {
                        method: 'delete'
                    })
                        .then(res => res.json())
                        .then(data => {
                            alert('The news headline has been removed');
                            this.fetchHeadlines();
                        })
                        .catch(err => console.log(err));
                }
            },/* end deleteHeadline */

            addHeadline() {
                if (this.edit === false) {
                    //Add this new news headline
                    fetch('api/Headline', {
                        method: 'post',/*
                        description: JSON.stringify(this.headline),
                        content: JSON.stringify(this.headline),*/
                        headers: {
                            'content-type': 'application/json'
                        }
                    })
                    .then(res => res.json)
                    .then(data => {
                        this.headline.title = '';
                        this.headline.identity= '';
                        this.headline.name= '';
                        this.headline.title= '';
                        this.headline.description= '';
                        this.headline.url= '';
                        this.headline.urlToImage= '';
                        this.headline.publishedAt= '';
                        this.headline.content= '';
                        this.headline.category= '';
                        this.headline.language= '';
                        this.headline.country= '';
                        this.headline.diskImageFileName= '';
                        this.headline.created_at= '';
                        this.headline.updated_at= '';
                        alert('Your News Headline has been added. Thanks for the contribution.');
                        this.fetchHeadlines();
                    })
                }
                else {
                    //Just update
                    fetch('api/Headline', {
                        method: 'put',
                        description: JSON.stringify(this.headline),
                        content: JSON.stringify(this.headline),
                        headers: {
                            'content-type': 'application/json'
                        }
                    })
                    .then(res => res.json)
                    .then(data => {
                        this.headline.title = '';
                        this.headline.identity= '';
                        this.headline.name= '';
                        this.headline.title= '';
                        this.headline.description= '';
                        this.headline.url= '';
                        this.headline.urlToImage= '';
                        this.headline.publishedAt= '';
                        this.headline.content= '';
                        this.headline.category= '';
                        this.headline.language= '';
                        this.headline.country= '';
                        this.headline.diskImageFileName= '';
                        this.headline.created_at= '';
                        this.headline.updated_at= '';
                        alert('Your News Headline has been updated. Thanks for the contribution.');
                        this.fetchHeadlines();
                    })
                }
            },/* end addHeadline */

            editHeadline(headline) {
                this.edit = true;
                this.headline.id = headline.id;
                this.headline.headline_id = headline.id;
                this.headline.identity = headline.identity;
                this.headline.name = headline.name;
                this.headline.title = headline.title;
                this.headline.description = headline.description;
                this.headline.url = headline.url;
                this.headline.urlToImage = headline.urlToImage;
                this.headline.publishedAt = headline.publishedAt;
                this.headline.content = headline.content;
                this.headline.category = headline.category;
                this.headline.language = headline.language;
                this.headline.country = headline.country;
                this.headline.diskImageFileName = headline.diskImageFileName;
                this.headline.created_at = headline.created_at;
                this.headline.updated_at = headline.updated_at;
            }
        }
    };
</script>

Frontend page, 'layouts.headline':

<!doctype html>
<html lang="">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <!-- Protect against cross site forgery -->
        <meta name="csrf-token" content="">
        <script>
            window.Laravel = { csrfToken: '' }
        </script>

        <link href="" rel="stylesheet">

        <!-- Title of this page -->
        <title>News Headlines with Vue</title>

        <!-- Fonts -->
        <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">
    </head>
    <body>
        <div id="app">
            <navbar></navbar>
            <div class="container">
                <headlines></headlines>
            </div>
        </div>

        <link href="">
        <link href="">
        <link href="">
        <script src=""></script>
    </body>
</html>

Pardon me, for the lengthy code. 'Just want to give full info.



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire