Attempt to read property "users_id" on null - laravel-8

I am facing this error:
Attempt to read property "users_id" on null
in Laravel 8 controller.
public function editData88(Request $request, $id)
{
$id = Auth::user()->id;
$user = User::where('id', $id)->with(['detail_data' => function ($query) {
$query->with('agama');
}])->first();
$data_agama = Agama88::all();
return view('crud.edit88', compact('user', 'data_agama', 'id'));
}
Blade
<div class="form-group">
<label for="exampleInputPassword1">Alamat</label>
#if ($user->id == $user->detail_data->users_id)
<input type="text" class="form-control" id="alamat" name="alamat"
value="{{ $user->detail_data->alamat }}">
#else
<input type="text" class="form-control" id="alamat" name="alamat"
placeholder="Masukkan Alamat">
#endif
</div>
Model
public function detail_data()
{
// return $this->belongsTo(detail_data::class);
return $this->hasOne(Data88::class, "users_id", "id");
}
How to fix the error?

Do you have a relation called agama? If not, you shouldn't use
$query->with('agama');
From the available code, I suggest to try:
$user = User::where('id', $id)->with('detail_data')->first();

Assuming having no detail_data on a user isn't a bug you can change your if statement to this:
#if ($user->id == $user->detail_data?->users_id)
This way if you have no detail_data it will return null instead of trying to read user_id on null.

Related

Call to a member function update() on null in laravel 9

What is wrong with this function? I ve got error on this line:
$bookShelf->update($request->all());
My Controller
<?php
namespace App\Http\Controllers;
use App\Models\BookShelf;
use App\Models\Book;
use App\Models\Category;
use App\Http\Requests\StoreBookShelfRequest;
use App\Http\Requests\UpdateBookShelfRequest;
class BookShelfController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$bookshelves = BookShelf::with('book')->latest()->get();
// $bookshelves = BookShelf::all();
$model = new BookShelf();
$books = Book::with('category')->latest()->get();
// $books = Book::all();
$categories = Category::with(['users.books.shelf']);
return view('admin.bookshelves.index', compact('bookshelves', 'books', 'model', 'categories'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
$model = new BookShelf;
$categories = Category::all();
$books = Book::with('category')->latest()->get();
return view('admin.bookshelves.create', compact('categories', 'model', 'books'));
}
/**
* Store a newly created resource in storage.
*
* #param \App\Http\Requests\StoreBookShelfRequest $request
* #return \Illuminate\Http\Response
*/
public function store(StoreBookShelfRequest $request)
{
BookShelf::create($request->all());
return redirect('admin_area/shelves')->with('success', 'Selamat Data Berhasil Ditambahkan');
}
/**
* Display the specified resource.
*
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function show(BookShelf $bookShelf)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function edit($shelf_code)
{
$model = BookShelf::find($shelf_code);
$categories = Category::all();
$books = Book::with('category')->latest()->get();
return view('admin.bookshelves.edit', compact('categories', 'model', 'books'));
}
/**
* Update the specified resource in storage.
*
* #param \App\Http\Requests\UpdateBookShelfRequest $request
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function update(UpdateBookShelfRequest $request, BookShelf $bookShelf)
{
$bookShelf = BookShelf::find($bookShelf->shelfcode);
$bookShelf->update($request->all());
return redirect('admin_area/bookshelves')->with('success', 'Selamat Data Berhasil Di Ubah');
}
/**
* Remove the specified resource from storage.
*
* #param \App\Models\BookShelf $bookShelf
* #return \Illuminate\Http\Response
*/
public function destroy(BookShelf $bookShelf, $id)
{
$bookShelf = BookShelf::find($id);
$bookShelf->delete();
return redirect('admin_area/shelves')->with('success', "Data berhasil disimpan");
}
}
My Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class BookShelf extends Model
{
use HasFactory;
protected $guarded = ['id'];
protected $load = ['category', 'book'];
public function category()
{
return $this->belongsTo(Category::class);
}
public function book()
{
return $this->belongsTo(Book::class);
}
public function getRouteKeyName()
{
return 'shelfcode';
}
}
My Edit View
#extends('layouts.main')
#section('title', 'Edit Data Buku')
#section('content')
<div class="container">
<div class="row mt-3 d-flex justify-content-center">
<div class="col-md-9 justify-content-center">
<div class="card card-primary card-outline">
<div class="card-header">
<h5 class="m-0">Edit Data Rak Buku</h5>
</div>
<div class="card-body">
<h6 class="card-title"></h6>
<form method="POST" action="{{ route('shelves.update', $model->shelfcode) }}"
enctype="multipart/form-data">
#csrf
{{-- <input type="hidden" name="_method" value="PATCH"> --}}
#method('PUT')
#include('admin.bookshelves.form')
<div class="form-group">
<button class="btn btn-warning btn-sm glyphicon glyphicon-save">
<span class="fas fa-edit"> Edit Data Buku</span>
</button>
</div>
</form>
{{-- #endsection --}}
</div>
</div>
</div>
</div>
</div>
#endsection
Looks like you're querying your BookShelf model by the wrong key. You can also remove $bookShelf = BookShelf::find($bookShelf->shelfcode); from the update function since it is already injected by the framework when you use model binding (https://laravel.com/docs/9.x/routing#route-model-binding).
When you have this common error, there is no trap, it litteraly means that you are trying to call update on null.
It's exactly like doing null->update($request->all()) (and you can try, you'll have the same error).
The only explanation here is that $bookShelf = BookShelf::find($bookShelf->shelfcode); returns null.
Regarding the structure itself,
public function update(UpdateBookShelfRequest $request, BookShelf $bookShelf)
{
$bookShelf = BookShelf::find($bookShelf->shelfcode);
//...
}
makes no sense since the whole purpose of using implicit route binding is to avoid the manual query you are making to retrieve $bookShelf. It should already be the BookShelf you need.

Asp.Net Core - Display string list values in textarea?

I have a list whose values ​​are taken from the database,I want each of these values ​​to be displayed in a line in textarea...
Controller :
public async Task<IActionResult> AddOrEditPoll(Guid Id)
{
var polloptionList = await _admin.GetQuestionsListByPollId(Id);
PollViewModel model = new PollViewModel();
model.AnswerList = new List<string>();
foreach (var item in polloptionList)
{
model.AnswerList.Add(item.Answer);
};
return View(model);
}
View :
<div class="form-group">
<label class="control-label">Answer</label>
<textarea asp-for="AnswerList" class="form-control"></textarea>
</div>
ّI want it to be displayed as follows:
Can you guide me if you have a good solution?
You can try to replace asp-for with id and name,asp-for will set the value of textarea with AnswerList,and then convert AnswerList to string.Here is a demo:
Action:
public IActionResult AddOrEditPoll() {
PollViewModel model = new PollViewModel();
model.AnswerList = new List<string> { "answer1", "answer2" , "answer3" };
return View(model);
}
View:
<div class="form-group">
<label class="control-label">Answer</label>
<textarea name="AnswerList" class="form-control" style="text-align:right">#string.Join("\n ", Model.AnswerList)</textarea>
</div>
result:

livewire view don't send any xhr request to component

I have a select html tag in livewire view:
<select wire:model="categoryId" wire:change="$emit('attr_cat', $event.target.value)" name="category_id" class="form-control">
<option value="0">Select category</option>
#foreach($categories as $category)
<option value="{{$category->id}}">{{ $category->name }}</option>
#if(count($category->childs))
#include('admin.categories.subcategorylist',['childs' => $category->childs])
#endif
#endforeach
</select>
and a livewire component with following code:
namespace App\Http\Livewire\Admin;
use App\Models\Attribute;
use App\Models\Category;
use App\Models\CategoryAttribute;
use Barryvdh\Debugbar\Facade as Debugbar;
use Livewire\Component;
class CategoryAttributes extends Component
{
public $attributeId;
public $categoryId;
public $attributeCategories;
public $categories;
protected $listeners = ['attr_cat' => 'addAttributeToCategory'];
public function mount()
{
$this->attributeCategories = Attribute::find($this->attributeId)->categories()->get();
$this->categories = Category::whereNull('category_id')->orderBy('name')->with('childs')->get();
$this->categoryId = 0;
}
public function render()
{
return view('livewire.admin.category-attributes');
// return view('livewire.admin.cat-attr-test');
}
public function addAttributeToCategory($value){
Debugbar::addMessage($value);
CategoryAttribute::create([
'category_id' => $this->categoryId,
'attribute_id' => $this->attributeId,
]);
}
public function updatedCategoryId(){
Debugbar::addMessage($this->attributeId);
}
}
and mount livewire component with this line in my blade view:
#livewire('admin.category-attributes', ['attributeId' => $attribute->id], key('attr-'.$attribute->id))
but, when I change selected item, nothing happens and no xhr requests are sent to the server by the browser.
Let me say this too, I have inserted #livewireStyles and #livewireScripts in master blade file and they are loaded correctly.
Thank you for your help.
I found the solution to my problem. I had to put all the contents of the view in a standalone tag so that livewire could assign an ID to it. Otherwise, livewire will refuse to send any request to the server. 

Conditional Attributes that is not boolean in blazor

I am trying to generate my own component with checkbox system to know if I need the attribute or not (of type int / float etc)
<input type="checkbox" #bind="isMinInt" />
#if (isMinInt == true) {
<input type="number" #bind="MinInt"/>
}
So I would like to replace this #if:
#if(isMinInt == true) {
<MyComponent #bind-Value="ValueInt" Min="#MinInt"/>
} else {
<MyComponent #bind-Value="ValueInt"/>
}
by something like
<MyComponent #bind-Value="ValueInt"
#if(isMinInt == true ? Min="#MinInt" : String.Empty />
because I will have many attributes on my component and I would like to make it simplier
EDIT + Solution
Now using the #attributes:
<input type="checkbox" #bind="isMinInt" />
#if (isMinInt == true) {
<input type="number" #bind="MinInt" />
}
<MyComponent #bind-Value="ValueInt" #attributes="GetAttributesInt()" />
#code {
private bool isMinInt = false;
private int MinInt;
private IDictionary<string, object> GetAttributesInt() {
var dict = new Dictionary<string, object>() { };
if (isMinInt)
dict.Add("Min", MinInt);
return dict;
}
}
EDIT + Solution 2
Now using the #attributes:
<input type="checkbox" #bind="isMinInt" />
#if (isMinInt == true) {
<input type="number" #bind="MinInt" />
}
<MyComponent #bind-Value="ValueInt" #attributes="GetAttributesInt()" />
#code {
private bool isMinInt = false;
private int MinInt;
private IDictionary<string, object> GetAttributesInt() {
var dict = new Dictionary<string, object>() { };
dict["Min"] = this.isMinInt ? MinInt : Int32.MinValue;
return dict;
}
}
The reason why I'm using Int32.MinValue it's because MyComponent correspond to an <input type="number"> where his min is bind to my MinInt, so if I use 0 in the place of Int32.MinValue it won't allow me to go for negative numbers.
I will have many attributes on my component and I would like to make it simplier
You can't do that directly. However, as a walkaround, you can use the #attributes to bind attributes dynamically. For example:
<MyComponent #bind-Value="ValueInt" #attributes="#a_dictionary_expression" />
Where #a_dictionary_expression is a C# expression that can be evaluated at runtime. What's more, you can even create a custom function to calculate the dictionary:
<MyComponent #bind-Value="ValueInt" #attributes="getAttributes()" /gt;
#code {
...
private IDictionary getAttributes()
{
var dict = new Dictionary(){};
if(isMinInt) {
dict.Add("Min", $"{MinInt}");
} // this will introduce a bug, see Edit2 for more details
return dict ;
}
}
[Edit]: Here's a way to render the attributes within a single line
<input #bind-Value="ValueInt" #attributes="#(isMinInt? new Dictionary<string,object>{ Min= #Min} : new Dictionary<string,object>{})" />
[Edit2]
The above code will introduce a bug that the MyComponent is not updated correctly. The reason is the parameters of <MyComponent> received from previous #attributes is not automatically cleared when a new #attributes received.
For example,
the first time #attributes is {Min=1}, and it results in a statement:
MyComponent.Min=1;
The second time #attributes is {}, because there's no attribute inside it, it won't assign parameters for it, thus the MyComponent.Min remains the same.
To fix that, change the above code as below:
private IDictionary<string, object> GetAttributesInt() {
var dict = new Dictionary<string, object>() { };
dict["Min"] = this.isMinInt ? MinInt : 0 ;
return dict;
}
I used this simple solution and it work, hope this help you too:
<input id="#InputId" aria-labelledby="#(!string.IsNullOrWhiteSpace(InputId) ? "this is test" : null)">

View takes values from query string instead of model

I have an action in my controller:
public PartialViewResult MyAction(int? myId, int? myId2)
{
MyModel model = new MyModel() { MyId = 10, MyId2 = 20 }
return PartialView(model);
}
Here is my view:
#model StartSite.Models.Shared.MyModel
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.MyId)
#Html.HiddenFor(m => m.MyId2)
<p>
<input type="submit" value="Submin" />
</p>
}
Lets call MyAction with params myId=1&myId2=2. But the model is created with different values new MyModel() { MyId = 10, MyId2 = 20 }. And what should be rendered in view? As I expect it should be:
<input id="MyId" name="MyId" type="hidden" value="10">
<input id="MyId2" name="MyId2" type="hidden" value="20">
But in fact the result is:
<input id="MyId" name="MyId" type="hidden" value="1">
<input id="MyId2" name="MyId2" type="hidden" value="2">
As I guess the Html.HiddenFor takes values not from my model but from Reauest.QueryString which is myId=1&myId2=2 at the moment the view is rendered.
Why it happens? Is it expected behaviour?
UPDATE 1:
I've edited my question to be more clear.
to have access to the Model in the submit try with this
[HttpPost]
public virtual PartialViewResult MyAction(MyModel model)
{
//MyModel model = new MyModel();
// if (myId != null)
// model.MyId= myId;
// else if (myId2 != null)
// model.MyId2= myId2;
//now you have access to your model values
return PartialView(model);
}
This is expected behavior. Firstly, an Action without any Attributes is automatically a HttpGet. Next, your Action expects a value for 'myId'. This means, if the url calling your Action has a querystring that matches, it'll accept the value. Finally, the value your Action accepts is case-insensitive. Therefore, you do not need to manually set your model values. You can simply do this:
public virtual PartialViewResult MyAction(MyModel model)
{
return PartialView(model);
}
So when you go to your url, e.g. localhost/myaction?myId=2, model.MyId will be set to 2.
If you do NOT want your model set by a querystring, you must change your Action to not accept any values.