Search code examples
laravelvue.jsaxiosvuex

Vuex and Laravel 5: how to remove Tags from Articles


I have a small blog app that has Articles and Tags. Nothing fancy so far. Every Article can have many Tags.

The Laravel backend delivers the data via API calls from Axios in the Vue Frontend. In the Laravel models Article has a method

public function tags(){
        return $this->belongsToMany('App\Tag');
    }

and vice versa for tags. I have a pivot table and all this follow pretty much the example given in https://laracasts.com/series/laravel-5-fundamentals/episodes/21 All this works fine.

Now let´s say I want to call in Vue the method deleteTag() which should remove the connection between Article and Tag. Things are behind the scenes a bit more complicated as "addTag" in PHP also adds a new Tag Model AND the connection between Tag and Article in the Pivot table OR connects - if the Tag exists already - an existing Tag with Article.

What is the best way to achieve this?

What I´m doing so far:

ArticleTags.vue

    deleteTag(tagName){
            let articleId = this.articleId;
            this.$store.dispatch('removeTagFromArticle', { articleId, tagName });
      },

index.js (Vuex store)

actions: {
    removeTagFromArticle(context,param) {
       axios.post('api/articles/delete-tag/', param)
                    .then((res) => {
                        let article = context.getters.getArticleById(param.articleId);
                        let tagName =  param.tagName;
                        context.commit('deleteTag', {article, tagName} );
                    })
                    .catch((err) => console.error(err));

    } }

mutations : {    deleteTag (state, { article, tag }) {
      let tagIndex = article.tags.indexOf(tag);
      article.tags.splice(tagIndex,1);
    } }

ArticleController.php

 /**
 * Remove Tag from Article
 *
 * @param  \Illuminate\Http\Request  $request
 * @return \Illuminate\Http\Response
 */
public function deleteTag(Request $request)
{   
    $tag = \App\Tag::firstOrCreate(array('name' => $request->tagName));
    $article = Article::findOrFail($request->articleId);

    $result = $article->tags()->detach([$tag->id]);

    $this->cleanUpTags();

    return response('true', 200);
}

routes/web.php

Route::post('api/articles/delete-tag', 'ArticleController@deleteTag');

This works so far. The code does exactly what it should. Only it feels really clumsy. And probably to complicated. Maybe it´s because the example is simple but the whole setup is big. Nonetheless I´m trying to improve my coding. :)

So my questions are:

1) Would it be better to pass the article object in Vue to the store instead of the articleId?

2) Is the idea of using Array.slice() in the store too complicated? This could be done straight in the components.

3) Does it make sense to reload the whole store from Laravel after deleting the tag PHP-wise?

Edit: in case someone is looking for this question and how I solved it at the end. The source code for this app can be found at https://github.com/shopfreelancer/streamyourconsciousness-laravel


Solution

  • Personally I like to use ID's to reference any database resource aswell as keeping my objects in javascript somewhat the same as my API.

    1

    In this case I would have changed my tags to objects instead of strings and send an ID of the tag to my API.

    An example of my article would look like:

    let article = {
        tags: [{ id: 1, name: 'tag 1' }, { id: 2 ... }]
    }
    

    Using objects or IDs as parameters are in my opinion both fine. I should stick with objects if you like "cleaner" code, there will only be one place to check if the ID is present in your object aswell as the selection of the ID.

    Case:

    // Somehwere in code
    this.deleteArticle(article);
    
    // Somehwere else in code
    this.deleteArticle(article);
    
    // Somewhere else in code
    this.deleteArticle(article);
    
    // Function
    deleteArticle(article) {
      // This check or other code will only be here instead of 3 times in code
      if (!article.hasOwnProperty('id')) {
        console.error('No id!');
      }
    
      let id = article.id;
    
      ...
    }
    

    2

    Normally I would keep the logic of changing variables in the components where they are first initialized. So where you first tell this.article = someApiData;. Have a function in there that handles the final removal of the deleted tag.

    3

    If you are looking for ultimate world domination performance I would remove the tag in javascript. You could also just send the updated list of tags back in the response and update all tags of the article with this data and keep your code slim. However I still like to slice() the deleted tag from the array.

    Remember this is my opinion. Your choises are completely fine and you should, like I do myself, never stop questioning yours and others code.