mlazuardy's avatar

Creating default object from empty value (post update)

Sorry again if i make too much problem hehe,

im forget to use to update the post, did you guys have a solutions for this

"Creating default object from empty value"

the PostController@update is

    public function update(Request $request,$id)
    {
      // Validate the data

      $this->validate(request(),[
        'title'    =>'required|max:50',
        'body'    =>'required',
        'excerpt' =>'required',
        'category_id'  =>'required',

      ]);
         // Save the data to the database
         $post = Post::find($id);
         $post->title = $request->title;
         $post->body  = $request->body;
         $post->slug  = str_slug($request->title);
         $post->excerpt = $request->excerpt;
         $post->category_id = $request->category_id;
         $post->meta_description = $request->excerpt;
         $post->meta_keywords = $request->title;
         $post->seo_title    = $request->title;
         if ($request->hasFile('image')) {
           $request->file('image')->store('public/posts/');
           $post->image = $request->file('image')->hashName('posts/');
                                         }
              $tags_id = [];
                  if ($request->tags) {
                      $tags = explode(',', $request->tags);
                      foreach ($tags as $tag) {
                          $tag_ref = Tag::firstOrCreate(['name' => str_slug($tag,'-')]);
                          $tags_id[] = $tag_ref->id;
                      }
                  }
                  $post->save();
                   Alert::message('Selanjutnya akan di Review Oleh Admin', 'Artikel Sukses di Update')->persistent('close');
                    $post->tags()->sync($tags_id);
             return redirect('/profile/post')->with('success','Post Berhasil dibuat');
    }

whoops say the problem is here

$post->title = $request->title;
0 likes
19 replies
tykus's avatar

Post::find($id) is returning null - you are trying to assign to a property on null.

You should use findOrFail($id) instead, or otherwise check that a Post instance has been returned so that your method errors out before you start assignment.

1 like
mlazuardy's avatar

so i wanna ask something, if find($id) is return to null, whats mean Post new();?

tykus's avatar

find($id) returns null because the is no Post with the given id in your database (or it has been soft-deleted).

new() will create a new instance of Post, but you wouldn't want that in the case of an update action

mlazuardy's avatar

i already make fixed the problem, but i have a problem again sir

    public function edit(Request $request,$id)
    {
      $post = Post::with('tags')->find($id);

      if(is_null($post)){
        abort(404);
      }
      if($post->author_id != Auth::user()->id){
        abort(404);
      }

      $categories = Category::all();
      $tags = Tag::all()->pluck('name','id');
      $tags = [];
                foreach ($post->tags as $tag) {
                    array_push($tags, $tag->name);
                }
      if ($post->status == 'PUBLISHED') {
        abort(404);
      }

      return view('post.edit',compact('post','categories','tag'));
    }

this Edit method, just show 1 latest tag in my view, not all tags the view is

        <input type="text" name="tags" id="tags" value="{{$tag->name}}" class="form-control">
tykus's avatar

So, this is a new issue, right?

You are sending to the view tag (singular) not tags (plural) so the last item in the $post->tags collection is being sent to the view because at that point it is the last Tag assigned to $tag.

Also, you are not using $tags = Tag::all()->pluck('name','id');, since $tags is immediately reassigned to an empty array.

Here is what my method would look like, by incorporating all of the checks into the query, you can rely on Laravel handling the 404's:

public function edit(Request $request,$id)
{
    $post = auth()->user()->posts() // assumes a posts() relation on User model
        ->with('tags')
        ->where('status', '!==', 'PUBLISHED')
        ->findOrFail($id); // automatically returns a ModelNotFoundException (404)

    $categories = Category::all();
    $tags = $post->tags->map(function ($tag) {
        return $tag->name;
    });

    return view('post.edit',compact('post', 'categories', 'tags'));
}

Then in the view, given you are (for some reason) listing all of the tags in a single text field:

<input type="text" name="tags" id="tags" value="{{implode(' ', $tags)}}" class="form-control">
mlazuardy's avatar

i do what you reply and its return to whoops

implode(): Invalid arguments passed (View: D:\XAMPP\htdocs\commit\resources\views\post\edit.blade.php)"
MaverickChan's avatar

@mlazuardy i guess it's your datas in the database have been corrupted.

Try truncate the table to check if everything is ok

tykus's avatar

Before you truncate anything, lets try to solve the actual error that was reported.

So, the idea behind implode is to join the elements of an array ($tags) together using a glue (' ') to give a single string representation of all the tags associated with the post. I suspected that this wasn't going to be useful, but because you were attempting to output tags into a single text field, I played along. So, what is it that you want to do with the tags array in your view?

mlazuardy's avatar

im making Article Web and the tags array is used for editing the Article/Post, so when User create user Post, it became draft and still can edit his Post, So when user edit the Post, it will show the last tags they input from Create/store , to Edit/update like this

https://i.imgur.com/qzX5TWn.png

the image i insert above, i upload yesterday. but now i delete the implode from your reply and remain the {{ $tags }} , it return all last inserted tags from the users, but also its curve "[]" and its tick (" " )

mlazuardy's avatar

it return

Collection {#637 ▼
  #items: array:2 [▼
    0 => "motherfucker"
    1 => "siapaya"
  ]
}
``
tykus's avatar

What you really need is a tags input rather than a simple text field, e.g. https://bootstrap-tagsinput.github.io/bootstrap-tagsinput/examples/ I know this is bootstrap-specifiy, but there might be something for available for your chosen CSS framework; or a jQuery plugin. In any case, you want the tag list to be maintained as an array of values and not a simple string.

If, however, you want to persist with the string approach, try the following in your controller instead of implode approach:

$tags = $post->tags->map(function ($tag) {
    return $tag->name;
})->reduce(function ($result, $tagName) {
    return $result .= " {$tagName}";
}, "");
newbie360's avatar

so what the result u want in the view ?

try

<input type="text" name="tags" id="tags" value="{{ $tags->implode(' ') }}" class="form-control">
mlazuardy's avatar

im already use that sir. need a js too? here it is

/*
    jQuery Tags Input Plugin 1.3.3
    Copyright (c) 2011 XOXCO, Inc
    Documentation for this plugin lives here:
    http://xoxco.com/clickable/jquery-tags-input
    Licensed under the MIT license:
    http://www.opensource.org/licenses/mit-license.php
    [email protected]
*/

(function($) {

    var delimiter = new Array();
    var tags_callbacks = new Array();
    $.fn.doAutosize = function(o){
        var minWidth = $(this).data('minwidth'),
            maxWidth = $(this).data('maxwidth'),
            val = '',
            input = $(this),
            testSubject = $('#'+$(this).data('tester_id'));

        if (val === (val = input.val())) {return;}

        // Enter new content into testSubject
        var escaped = val.replace(/&/g, '&amp;').replace(/\s/g,' ').replace(/</g, '&lt;').replace(/>/g, '&gt;');
        testSubject.html(escaped);
        // Calculate new width + whether to change
        var testerWidth = testSubject.width(),
            newWidth = (testerWidth + o.comfortZone) >= minWidth ? testerWidth + o.comfortZone : minWidth,
            currentWidth = input.width(),
            isValidWidthChange = (newWidth < currentWidth && newWidth >= minWidth)
                                 || (newWidth > minWidth && newWidth < maxWidth);

        // Animate width
        if (isValidWidthChange) {
            input.width(newWidth);
        }


  };
  $.fn.resetAutosize = function(options){
    // alert(JSON.stringify(options));
    var minWidth =  $(this).data('minwidth') || options.minInputWidth || $(this).width(),
        maxWidth = $(this).data('maxwidth') || options.maxInputWidth || ($(this).closest('.tagsinput').width() - options.inputPadding),
        val = '',
        input = $(this),
        testSubject = $('<tester/>').css({
            position: 'absolute',
            top: -9999,
            left: -9999,
            width: 'auto',
            fontSize: input.css('fontSize'),
            fontFamily: input.css('fontFamily'),
            fontWeight: input.css('fontWeight'),
            letterSpacing: input.css('letterSpacing'),
            whiteSpace: 'nowrap'
        }),
        testerId = $(this).attr('id')+'_autosize_tester';
    if(! $('#'+testerId).length > 0){
      testSubject.attr('id', testerId);
      testSubject.appendTo('body');
    }

    input.data('minwidth', minWidth);
    input.data('maxwidth', maxWidth);
    input.data('tester_id', testerId);
    input.css('width', minWidth);
  };

    $.fn.addTag = function(value,options) {
            options = jQuery.extend({focus:false,callback:true},options);
            this.each(function() {
                var id = $(this).attr('id');

                var tagslist = $(this).val().split(delimiter[id]);
                if (tagslist[0] == '') {
                    tagslist = new Array();
                }

                value = jQuery.trim(value);

                if (options.unique) {
                    var skipTag = $(this).tagExist(value);
                    if(skipTag == true) {
                        //Marks fake input as not_valid to let styling it
                        $('#'+id+'_tag').addClass('not_valid');
                    }
                } else {
                    var skipTag = false;
                }

                if (value !='' && skipTag != true) {
                    $('<span>').addClass('tag').append(
                        $('<span>').text(value).append('&nbsp;&nbsp;'),
                        $('<a>', {
                            href  : '#',
                            title : 'Removing tag',
                            text  : 'x'
                        }).click(function () {
                            return $('#' + id).removeTag(escape(value));
                        })
                    ).insertBefore('#' + id + '_addTag');

                    tagslist.push(value);

                    $('#'+id+'_tag').val('');
                    if (options.focus) {
                        $('#'+id+'_tag').focus();
                    } else {
                        $('#'+id+'_tag').blur();
                    }

                    $.fn.tagsInput.updateTagsField(this,tagslist);

                    if (options.callback && tags_callbacks[id] && tags_callbacks[id]['onAddTag']) {
                        var f = tags_callbacks[id]['onAddTag'];
                        f.call(this, value);
                    }
                    if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
                    {
                        var i = tagslist.length;
                        var f = tags_callbacks[id]['onChange'];
                        f.call(this, $(this), tagslist[i-1]);
                    }
                }

            });

            return false;
        };

    $.fn.removeTag = function(value) {
            value = unescape(value);
            this.each(function() {
                var id = $(this).attr('id');

                var old = $(this).val().split(delimiter[id]);

                $('#'+id+'_tagsinput .tag').remove();
                str = '';
                for (i=0; i< old.length; i++) {
                    if (old[i]!=value) {
                        str = str + delimiter[id] +old[i];
                    }
                }

                $.fn.tagsInput.importTags(this,str);

                if (tags_callbacks[id] && tags_callbacks[id]['onRemoveTag']) {
                    var f = tags_callbacks[id]['onRemoveTag'];
                    f.call(this, value);
                }
            });

            return false;
        };

    $.fn.tagExist = function(val) {
        var id = $(this).attr('id');
        var tagslist = $(this).val().split(delimiter[id]);
        return (jQuery.inArray(val, tagslist) >= 0); //true when tag exists, false when not
    };

   // clear all existing tags and import new ones from a string
   $.fn.importTags = function(str) {
      var id = $(this).attr('id');
      $('#'+id+'_tagsinput .tag').remove();
      $.fn.tagsInput.importTags(this,str);
   }

    $.fn.tagsInput = function(options) {
    var settings = jQuery.extend({
      interactive:true,
      defaultText:'add a tag',
      minChars:0,
      autocomplete: {selectFirst: false },
      hide:true,
      delimiter: ',',
      unique:true,
      removeWithBackspace:true,
      placeholderColor:'#666666',
      autosize: true,
      comfortZone: 20,
      inputPadding: 6*2
    },options);

        var uniqueIdCounter = 0;

        this.each(function() {
         // If we have already initialized the field, do not do it again
         if (typeof $(this).attr('data-tagsinput-init') !== 'undefined') {
            return;
         }

         // Mark the field as having been initialized
         $(this).attr('data-tagsinput-init', true);

            if (settings.hide) {
                $(this).hide();
            }
            var id = $(this).attr('id');
            if (!id || delimiter[$(this).attr('id')]) {
                id = $(this).attr('id', 'tags' + new Date().getTime() + (uniqueIdCounter++)).attr('id');
            }

            var data = jQuery.extend({
                pid:id,
                real_input: '#'+id,
                holder: '#'+id+'_tagsinput',
                input_wrapper: '#'+id+'_addTag',
                fake_input: '#'+id+'_tag'
            },settings);

            delimiter[id] = data.delimiter;

            if (settings.onAddTag || settings.onRemoveTag || settings.onChange) {
                tags_callbacks[id] = new Array();
                tags_callbacks[id]['onAddTag'] = settings.onAddTag;
                tags_callbacks[id]['onRemoveTag'] = settings.onRemoveTag;
                tags_callbacks[id]['onChange'] = settings.onChange;
            }

            var markup = '<div id="'+id+'_tagsinput" class="tagsinput"><div id="'+id+'_addTag">';

            if (settings.interactive) {
                markup = markup + '<input id="'+id+'_tag" value="" data-default="'+settings.defaultText+'" />';
            }

            markup = markup + '</div><div class="tags_clear"></div></div>';

            $(markup).insertAfter(this);

            $(data.holder).css('width',settings.width);
            $(data.holder).css('min-height',settings.height);
            $(data.holder).css('height',settings.height);

            if ($(data.real_input).val()!='') {
                $.fn.tagsInput.importTags($(data.real_input),$(data.real_input).val());
            }
            if (settings.interactive) {
                $(data.fake_input).val($(data.fake_input).attr('data-default'));
                $(data.fake_input).css('color',settings.placeholderColor);
                $(data.fake_input).resetAutosize(settings);

                $(data.holder).bind('click',data,function(event) {
                    $(event.data.fake_input).focus();
                });

                $(data.fake_input).bind('focus',data,function(event) {
                    if ($(event.data.fake_input).val()==$(event.data.fake_input).attr('data-default')) {
                        $(event.data.fake_input).val('');
                    }
                    $(event.data.fake_input).css('color','#000000');
                });

                if (settings.autocomplete_url != undefined) {
                    autocomplete_options = {source: settings.autocomplete_url};
                    for (attrname in settings.autocomplete) {
                        autocomplete_options[attrname] = settings.autocomplete[attrname];
                    }

                    if (jQuery.Autocompleter !== undefined) {
                        $(data.fake_input).autocomplete(settings.autocomplete_url, settings.autocomplete);
                        $(data.fake_input).bind('result',data,function(event,data,formatted) {
                            if (data) {
                                $('#'+id).addTag(data[0] + "",{focus:true,unique:(settings.unique)});
                            }
                        });
                    } else if (jQuery.ui.autocomplete !== undefined) {
                        $(data.fake_input).autocomplete(autocomplete_options);
                        $(data.fake_input).bind('autocompleteselect',data,function(event,ui) {
                            $(event.data.real_input).addTag(ui.item.value,{focus:true,unique:(settings.unique)});
                            return false;
                        });
                    }


                } else {
                        // if a user tabs out of the field, create a new tag
                        // this is only available if autocomplete is not used.
                        $(data.fake_input).bind('blur',data,function(event) {
                            var d = $(this).attr('data-default');
                            if ($(event.data.fake_input).val()!='' && $(event.data.fake_input).val()!=d) {
                                if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
                                    $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
                            } else {
                                $(event.data.fake_input).val($(event.data.fake_input).attr('data-default'));
                                $(event.data.fake_input).css('color',settings.placeholderColor);
                            }
                            return false;
                        });

                }
                // if user types a default delimiter like comma,semicolon and then create a new tag
                $(data.fake_input).bind('keypress',data,function(event) {
                    if (_checkDelimiter(event)) {
                        event.preventDefault();
                        if( (event.data.minChars <= $(event.data.fake_input).val().length) && (!event.data.maxChars || (event.data.maxChars >= $(event.data.fake_input).val().length)) )
                            $(event.data.real_input).addTag($(event.data.fake_input).val(),{focus:true,unique:(settings.unique)});
                        $(event.data.fake_input).resetAutosize(settings);
                        return false;
                    } else if (event.data.autosize) {
                        $(event.data.fake_input).doAutosize(settings);

                    }
                });
                //Delete last tag on backspace
                data.removeWithBackspace && $(data.fake_input).bind('keydown', function(event)
                {
                    if(event.keyCode == 8 && $(this).val() == '')
                    {
                         event.preventDefault();
                         var last_tag = $(this).closest('.tagsinput').find('.tag:last').text();
                         var id = $(this).attr('id').replace(/_tag$/, '');
                         last_tag = last_tag.replace(/[\s]+x$/, '');
                         $('#' + id).removeTag(escape(last_tag));
                         $(this).trigger('focus');
                    }
                });
                $(data.fake_input).blur();

                //Removes the not_valid class when user changes the value of the fake input
                if(data.unique) {
                    $(data.fake_input).keydown(function(event){
                        if(event.keyCode == 8 || String.fromCharCode(event.which).match(/\w+|[áéíóúÁÉÍÓÚñÑ,/]+/)) {
                            $(this).removeClass('not_valid');
                        }
                    });
                }
            } // if settings.interactive
        });

        return this;

    };

    $.fn.tagsInput.updateTagsField = function(obj,tagslist) {
        var id = $(obj).attr('id');
        $(obj).val(tagslist.join(delimiter[id]));
    };

    $.fn.tagsInput.importTags = function(obj,val) {
        $(obj).val('');
        var id = $(obj).attr('id');
        var tags = val.split(delimiter[id]);
        for (i=0; i<tags.length; i++) {
            $(obj).addTag(tags[i],{focus:false,callback:false});
        }
        if(tags_callbacks[id] && tags_callbacks[id]['onChange'])
        {
            var f = tags_callbacks[id]['onChange'];
            f.call(obj, obj, tags[i]);
        }
    };

   /**
     * check delimiter Array
     * @param event
     * @returns {boolean}
     * @private
     */
   var _checkDelimiter = function(event){
      var found = false;
      if (event.which == 13) {
         return true;
      }

      if (typeof event.data.delimiter === 'string') {
         if (event.which == event.data.delimiter.charCodeAt(0)) {
            found = true;
         }
      } else {
         $.each(event.data.delimiter, function(index, delimiter) {
            if (event.which == delimiter.charCodeAt(0)) {
               found = true;
            }
         });
      }

      return found;
   }
})(jQuery);

mlazuardy's avatar

the implode method is joining to array sir, its not what i want, i want all string seperate like the screenshot i post in above @newbie360

mlazuardy's avatar
mlazuardy
OP
Best Answer
Level 2

i guess it fixed with this

<input type="text" name="tags" id="tags" value="{{ $tags->implode(',') }}" class="form-control">

i use comma inside the ticks, now im trying to test the field , thanks for your help :) @newbie360 @tykus

tykus's avatar

typo... the reduce method takes two arguments - look at updated answer

Does the jQuery Tags Input Plugin take a string of space delimited, or comma delimited tags? If you need them to be comma-delimited, then the reduce part your be:

// ...
->reduce($result, $tagName) {
    return $result .= ", {$tagName}";
}, "");

Please or to participate in this conversation.