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.
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;
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.
so i wanna ask something, if find($id) is return to null, whats mean Post new();?
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
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">
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">
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)"
@mlazuardy i guess it's your datas in the database have been corrupted.
Try truncate the table to check if everything is ok
what is truncate ? how to deal with it? @MaverickChan im using XAMPP with phpmyadmin 4.7.0
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?
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 (" " )
dd($tags);
something wrong ?
it return
Collection {#637 ▼
#items: array:2 [▼
0 => "motherfucker"
1 => "siapaya"
]
}
``
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}";
}, "");
so what the result u want in the view ?
try
<input type="text" name="tags" id="tags" value="{{ $tags->implode(' ') }}" class="form-control">
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, '&').replace(/\s/g,' ').replace(/</g, '<').replace(/>/g, '>');
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(' '),
$('<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);
"Undefined variable: result"
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
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
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.