Member Since 1 Year Ago
1,930 experience to go until the next level!
In case you were wondering, you earn Laracasts experience when you:
Earned once you have completed your first Laracasts lesson.
Earned once you have earned your first 1000 experience points.
Earned when you have been with Laracasts for 1 year.
Earned when you have been with Laracasts for 2 years.
Earned when you have been with Laracasts for 3 years.
Earned when you have been with Laracasts for 4 years.
Earned when you have been with Laracasts for 5 years.
Earned when at least one Laracasts series has been fully completed.
Earned after your first post on the Laracasts forum.
Earned once 100 Laracasts lessons have been completed.
Earned once you receive your first "Best Reply" award on the Laracasts forum.
Earned if you are a paying Laracasts subscriber.
Earned if you have a lifetime subscription to Laracasts.
Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.
Earned once you have achieved 500 forum replies.
Earned once your experience points passes 100,000.
Earned once your experience points hits 10,000.
Earned once 1000 Laracasts lessons have been completed.
Earned once your "Best Reply" award count is 100 or more.
Earned once your experience points passes 1 million.
Earned once your experience points ranks in the top 50 of all Laracasts users.
Earned once your experience points ranks in the top 10 of all Laracasts users.
Started a new Conversation Retrieving The Non Authenticated User Id
i have an avatar attribute in my user model as below:
public function getAvatarAttribute()
{
$avatar = UserProfile::select('avatar')->where('user_id', auth()->id())->get()->implode('avatar', '');
if ($avatar)
{
return asset('storage/'.$avatar);
}
else
{
$default = "https://s3.amazonaws.com/37assets/svn/765-default-avatar.png";
$size = 400;
$hash = md5(strtolower(trim($this->attributes['email']))) . '?d=' . urlencode( $default ) . '&s=' . $size;
return "http://www.gravatar.com/avatar/$hash";
}
}
which is working fine for the logged in users but since I'm using route model binding to make the user profile visible to the public using the username in the URL Route::get('/@{user:username}', UserProfilePublic::class);
this doesn't work for the non authenticated users using {{$user->avatar}}
in the view like other user's info which I guess its because of the relational DB setup that I have in my app. I'm not sure how to make this work for both authenticated users and non-authenticated users. I'm sure need to change where('user_id', auth()->id())
to accept the user id of the user in which is returned by the route model binding and route key name but I'm not sure how to do it.
Awarded Best Reply on Validation Required Field Error After Resetting The Properties
found the issue. it was all because I forgot the type="button"
of the button.
Started a new Conversation Get Data From Table Excluding Those In An Array
I have a table with 3 columns name, slug, icon
and user can search in this table to find certain value and add it to the profile. currently I'm using the following code to get the data from the model:
$this->skillResults = Skill::where('slug', 'like', '%'.$this->skillsQuery.'%')->get();
i want to exclude the values that the user added to the profile to avoid adding the same value multiple times and the value already added by the user is available in an array so I want to exclude the values in this array from the search results. i used the following code but it didn't work and it just excludes the first attribute from the search results:
$this->skillResults = Skill::where('slug', 'like', '%'.$this->skillsQuery.'%')->where('slug', '<>', Arr::pluck($this->skillsSelected, 'slug'))->get();
any idea how can I achieve this?
Started a new Conversation Queue Laravel Fortify Emails
Is there a way to queue Laravel Fortify emails like other emails in Laravel to avoid the impact on the UI? like email verification emails that are sent by Fortify upon new user registration which keep the view on loading status until the email has been sent which is not a good user experience when the email server is busy or queued upand it might take few seconds for the email to be sent.
Replied to Validation Required Field Error After Resetting The Properties
found the issue. it was all because I forgot the type="button"
of the button.
Replied to Validation Required Field Error After Resetting The Properties
i had no intention of using lifecycle hooks and there is a submit button that fires up the function. Also, I checked the document and could not find an update
lifecycle hook but still, I changed it to changePassword
but still the same problem.
Replied to Validation Required Field Error After Resetting The Properties
The reason I said I'm not using real-time validation is because the link you provided was pointing to the real-time validation part of the document so I wanted to clarify that I have no intention of using real-time validation for this view. Also I'm pretty sure I can't use $this->passwordRules()
in the rules
as a property and not a function. I'm pretty sure about this because I had that issue before. you may use rules
as a property or function in livewire and Laravel with the difference I mentioned.
So I'm not sure why the validation is being called up on resetting the properties.
Replied to Validation Required Field Error After Resetting The Properties
Thanks for the reply but first I'm not using real-time validation. Second, if I use rules
as a property then I won't be able to use $this->passwordRules()
as a rule.
Replied to Validation Required Field Error After Resetting The Properties
public function rules()
{
return[
'current_password' => ['required', 'string'],
'new_password' => $this->passwordRules(),
];
}
public function updatePassword()
{
$user = Auth::user();
$this->validate();
if (Hash::check($this->current_password, $user->password)) {
User::where('id', $user->id)->update([
'password' => Hash::make($this->new_password),
]);
$this->sweetAlert('success', 'password updated successfully');
$this->reset(['current_password', 'new_password_confirmation', 'new_password']);
}
else
{
$this->sweetAlert('error', 'Incorrect current password.');
}
}
Started a new Conversation Validation Required Field Error After Resetting The Properties
I have an update user password form in my application which is working fine except when I reset the fields using $this->reset(['current_password', 'new_password_confirmation', 'new_password']);
then I get the The current password field is required
and The new password field is required
on my view. any Idea why and how to fix this?
Replied to Laravel Fortify Password Confirmation With Livewire
Thanks for the reply but after looking at the jetstream repository I found out that it's using the libraries and methods that are exclusive to Jetstream.
I just need to know how to send POST
and GET
requests to an endpoint using Livewire without refreshing the page.
Started a new Conversation Send POST Request To Fortify Using Livewire
I'm trying to create a SPA-like app with Turbolinks and Livewire and now I'm stuck in the stage the everything is working fine except sending POST
methods to fortify endpoints which not sure how to do so without having the page refresh and also be able to catch the session('status')
and errors with jantinnerezo/livewire-alert
package to have a complete SPA app with unified alerts and notification style.
Any idea how to do this?
Started a new Conversation Laravel Fortify Password Confirmation With Livewire
Im building an app using Laravel Fortify and Livewire and i know how to use Fortify to build a separate view for confirming the user's password before taking an action by adding the following code to the fortifyServiceProvider
Fortify::confirmPasswordView(function () {
return view('auth.confirm-password');
});
but i would like to know how can i have the user confirm their password in a modal perhaps before performing an action to avoid redirecting the user to another view to make that SPA feeling for the user since I'm using Turbolinks in the project as well.
Replied to Dd Doesn't Show The Attributes
You were right. limiting it worked.
for the last question, how can I get the value of the attribute name
where the value of the attribute slug
is equal to a specific value?
Replied to Dd Doesn't Show The Attributes
I understand but doesn't dd
suppose to let me see the content of a collection?
Started a new Conversation Dd Doesn't Show The Attributes
i have the following code
$this->skills = Skill::select('name', 'slug', 'icon')->get();
dd($this->skills);
but the output is this and I cant see the values while there is 130 records on DB.
Illuminate\Database\Eloquent\Collection {#1480 ▼
#items: array:130 [▼
0 => App\Models\Skill {#1481 ▼
#connection: "mysql"
#table: "skills"
#primaryKey: "id"
#keyType: "int"
+incrementing: true
#with: []
#withCount: []
#perPage: 15
+exists: true
+wasRecentlyCreated: false
#attributes: array:3 [ …3]
#original: array:3 [ …3]
#changes: []
#casts: []
#classCastCache: []
#dates: []
#dateFormat: null
#appends: []
#dispatchesEvents: []
#observables: []
#relations: []
#touches: []
+timestamps: true
#hidden: []
#visible: []
#fillable: []
#guarded: array:1 [ …1]
}
it shows there are 3 attributes but it's not expandable and when I try to access the slug
property I get the Property [slug] does not exist on this collection instance
error.
Replied to Nullable Url Validation Rules Returns "the Url Fromat Is Invalid"
Amazingly today after restarting the Nginx and MySQL the same rule which was not working yesterday started to work today with no issue. I'm really lost here. Never ever have seen such a thing regarding validation rules.
Replied to Nullable Url Validation Rules Returns "the Url Fromat Is Invalid"
This is a livewire application so im not using the $request
to get the passed values.
Replied to Nullable Url Validation Rules Returns "the Url Fromat Is Invalid"
Why is it causing the problem here? I have many arrays that I'm validating using the same method and all of them are working fine. Why suddenly it caused issue only for url validation and only for url validation?
Replied to Nullable Url Validation Rules Returns "the Url Fromat Is Invalid"
it is
$table->string('url')->nullable();
Started a new Conversation Nullable Url Validation Rules Returns "the Url Fromat Is Invalid"
my URL validation rules return the URL format is invalid
no matter what I pass to it even null which is supposed to skip the validation because of the nullable
modifier. I'm kinda lost here and I don't want to use regex. also when I change it from url
to string
it works even on null.
rule:
'certificates.*.url' => ['nullable', 'url', 'max:250']
dd output:
[▼
"id" => 3
"user_id" => 1
"name" => "test"
"school" => "test"
"url" => "https://www.google.com"
"date" => "2020-12-01"
"created_at" => "2020-11-30T23:27:34.000000Z"
"updated_at" => "2020-11-30T23:27:55.000000Z"
]
Replied to Why Is The Section Of My View Disappears On Render?
Apparently. that's something i didn't know also and there is no mention of its need to be unique in the Livewire docs as well.
Replied to Why Is The Section Of My View Disappears On Render?
No missing closing tags. as what i thought at first the $loop->index
was causing it and you were on the right track to having me change it to something else like $languages as $lindex => $language
but apparently even by doing that those two sections will still have the same wire:key
because of the loop iterations which returns 0,1,2
and so on in order. so by appending a string to the key like lang{{ $loop->index }}
they will be unique and therefore problem solved.
view:
<div class="card card-profile shadow-sm mt-4">
<div class="px-4 mt-4 mb-4">
<div class="h5 font-weight-bold mb-4">زبانهای خارجی</div>
<div class="heading text-muted mb-4">تنها مجاز به اضافه کردن ۳ زبان به پروفابل خود هستید.</div>
@foreach ($languages as $language)
<div class="card card-body mb-4" wire:key="lang{{ $loop->index }}" id="langauge_section_{{ $loop->index }}">
<div class="text-left"><span class="fa fa-trash text-gray language-delete" wire:click="removeLanguage({{ $loop->index }}, {{ !empty($language['id']) ? $language['id'] : 0 }})"></span></div>
<div class="row">
<div class="form-group col-md-6">
<label class="">زبان</label>
<select class="form-control form-control-alternative" wire:model="languages.{{ $loop->index }}.language_name">
<option value="" class="form-control" selected disabled>انتخاب زبان</option>
@foreach ($languageNames as $name)
<option value="{{ $name->abbreviation }}" class="form-control">{{ $name->language }}</option>
@endforeach
</select>
</div>
<div class="form-group col-md-6">
<label class="">میزان تسلط</label>
<select class="form-control form-control-alternative" wire:model="languages.{{ $loop->index }}.language_level">
<option value="" class="form-control" selected disabled>میزان تسلط</option>
@foreach ($languageLevels as $level)
<option value="{{ $level->level }}" class="form-control">{{ $level->name }}</option>
@endforeach
</select>
</div>
</div>
</div>
@endforeach
@error('languages.*.language_level')
<small class="text-warning">{{ $message }}</small>
@enderror
@error('languages.*.language_language')
<small class="text-warning">{{ $message }}</small>
@enderror
@if (count($languages) < 3)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addLanguage"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
</div>
</div>
Awarded Best Reply on Why Is The Section Of My View Disappears On Render?
The issue has been solved. the problem indeed was a DOM issue caused by multiple loop index.
Replied to Why Is The Section Of My View Disappears On Render?
The issue has been solved. the problem indeed was a DOM issue caused by multiple loop index.
Replied to Why Is The Section Of My View Disappears On Render?
So literally no one in the PHP, Laravel, and Livewire community knows how to deal with this issue?
Replied to How To Update The Value Of An Input Field With The Output Of A Function?
ah ok but that doesn't fix the issue. the main issue was having the value
of the input field equivalent to the output of that function so I can use wire:model
to bind it to a property. The function does change the text of the field but for some reason, it doesn't trigger the wire:model
.
Started a new Conversation How To Update The Value Of An Input Field With The Output Of A Function?
I have a date picker and it works fine but the problem is that when a date has been selected it doesn't update the value of the corresponding input field. the script apparently works using the class name so there will be multiple inputs declared as the date picker using the same class on the same page but I have to update the value of the input fields individually meaning if the user selects 11/28/2020
for input1 only input1 updates with the value, not the other inputs that have been declared as the date picker by the same class.
here is the date picker initialization code I'm using:
<script>
$('.persian-date').persianDatepicker({
"inline": false,
"format": "YYYY/MM/DD",
"viewMode": "day",
"initialValue": false,
"minDate": null,
"maxDate": null,
"autoClose": true,
"position": "auto",
"altFormat": "",
"altField": "",
"onlyTimePicker": false,
"onlySelectOnDate": false,
"calendarType": "persian",
"inputDelay": 800,
"observer": true,
"calendar": {
"persian": {
"locale": "fa",
"showHint": true,
"leapYearMode": "algorithmic"
},
"gregorian": {
"locale": "en",
"showHint": true
}
},
"navigator": {
"enabled": true,
"scroll": {
"enabled": true
},
"text": {
"btnNextText": "<",
"btnPrevText": ">"
}
},
"toolbox": {
"enabled": false,
"calendarSwitch": {
"enabled": false,
"format": "MMMM"
},
"todayButton": {
"enabled": false,
"text": {
"fa": "امروز",
"en": "Today"
}
},
"submitButton": {
"enabled": false,
"text": {
"fa": "تایید",
"en": "Submit"
}
},
"text": {
"btnToday": "امروز"
}
},
"timePicker": {
"enabled": false,
"step": 1,
"hour": {
"enabled": false,
"step": null
},
"minute": {
"enabled": false,
"step": null
},
"second": {
"enabled": false,
"step": null
},
"meridian": {
"enabled": false
}
},
"dayPicker": {
"enabled": true,
"titleFormat": "YYYY MMMM"
},
"monthPicker": {
"enabled": true,
"titleFormat": "YYYY"
},
"yearPicker": {
"enabled": true,
"titleFormat": "YYYY"
}
});
</script>
Started a new Conversation Why Is The Section Of My View Disappears On Render?
I have a view made with livewire and it contains two dynamically add sections for spoken languages and the other one for courses and certificates. The language section was working fine until I added the add certificates section. now when the user clicks on the add section for the certificate section to add a new one, one of the added language sections disappears and then will appear again once you add another one. I guess it will appear again once the view re-renders. I have been going back and force moving functions around from render
method to update/updated/hydrate/dehydrate
but got no luck. at first, I thought it had something to do with the $loop->index
that I use in my view but after changing that I realized it was not it. I'm hitting a dead-end here and can't figure out what's going on here.
I also made a screen record of what is happening so it might help: https://drive.google.com/file/d/1Hq2wTKcPvhs05SKFMICaRoOAzpSyj9Iz/view?usp=sharing
View section:
<!-- language section -->
<div class="card card-profile shadow-sm mt-4">
<div class="px-4 mt-4 mb-4">
<div class="h5 font-weight-bold mb-4">Spoken languages</div>
<div class="heading text-muted mb-4">you only can add 3 languages to your profile.</div>
@foreach ($languages as $lindex => $language)
<div class="card card-body mb-4" wire:key="{{ $lindex }}">
<div class="text-left"><span class="fa fa-trash text-gray language-delete" wire:click="removeLanguage({{ $lindex }}, {{ !empty($language['id']) ? $language['id'] : 0 }})"></span></div>
<div class="row">
<div class="form-group col-md-6">
<label class="" for="languageName">language</label>
<select class="form-control form-control-alternative" name="language-name" {{-- id="languageName" --}} wire:model="languages.{{ $lindex }}.language_name">
<option value="" class="form-control" selected disabled>select language</option>
@foreach ($language_names as $name)
<option value="{{ $name->abbreviation }}" class="form-control">{{ $name->language }}</option>
@endforeach
</select>
</div>
<div class="form-group col-md-6">
<label class="" for="languageProficiency">proficiency level</label>
<select class="form-control form-control-alternative" name="language-proficiency" {{-- id="languageProficiency" --}} wire:model="languages.{{ $lindex }}.language_level">
<option value="" class="form-control" selected disabled>proficiency level</option>
@foreach ($language_levels as $level)
<option value="{{ $level->level }}" class="form-control">{{ $level->name }}</option>
@endforeach
</select>
</div>
</div>
</div>
@endforeach
@error('languages.*.language_level')
<small class="text-warning">{{ $message }}</small>
@enderror
@error('languages.*.language_language')
<small class="text-warning">{{ $message }}</small>
@enderror
@if (count($languages) < 3)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addLanguage"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
</div>
</div>
<!-- end language section -->
<!-- other certificates section -->
<div class="card card-profile shadow-sm mt-4">
<div class="px-4 mt-4 mb-4">
<div class="h5 font-weight-bold mb-4">Other related certificates</div>
<div class="heading text-muted mb-4">if you have other related certificates in your files you can add then here.</div>
@foreach ($certificates as $cindex => $certificate)
<div class="card card-body mb-4" wire:key="{{ $cindex }}">
<div class="row">
<div class="form-group col-md-6">
<label class="" for="other-certificates-name">certificate name</label>
<input type="text" class="form-control form-control-alternative" placeholder="" name="ptherCertificatesName">
</div>
<div class="form-group col-md-6">
<label class="" for="other-certificates-school-name">School name</label>
<input type="text" class="form-control form-control-alternative" placeholder="" name="otherCertificatesSchoolName">
</div>
<div class="form-group col-md-6">
<label class="" for="other-certificates-verification-link">URL<small>(optional)</small></label>
<input type="text" class="form-control form-control-alternative text-left" placeholder="" name="otherCertificatesVerificationLink">
</div>
<div class="form-group col" dir="ltr">
<label class="" for="other-certificates-grad-date" dir="rtl">finished date</label>
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-calendar-grid-58"></i></span>
</div>
<input type="text" class="form-control form-control-alternative datePicker" placeholder="" name="otherCertificatesGradDate" value="">
</div>
</div>
</div>
</div>
@endforeach
@if (count($certificates) < 5)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addCertificate"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
</div>
</div>
<!-- end other certificates section -->
Livewire component controller:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\CityName;
use App\Models\Language;
use App\Models\LanguageLevel;
use App\Models\User;
use App\Models\UserLanguage;
use App\Models\UserProfile;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
class UserInfo extends Component
{
public $name;
public $email;
public $phone;
public $states = [];
public $selectedstate;
public $cities = [];
public $selectedcity;
public $jobTitle;
public $aboutMe;
public $employer;
public $position;
public $edu_course;
public $edu_school;
public $edu_level;
public $edu_start_date;
public $edu_end_date;
public $employment_looking;
public $employment_hired;
public $twitter;
public $linkedin;
public $github;
public $instagram;
public $website;
public $languages = [];
public $language_names;
public $language_levels;
public $languageToDelete = [];
public $certificates = [];
public $certificate_name;
public $certificate_school;
public $certificate_link;
public $certificate_date;
public $certificateToDelete = [];
public $skillsQuery;
public $skillResults;
public $skills;
public function render()
{
$this->retriveStates();
$this->retriveCities();
$this->retriveLanguages();
return view('livewire.user-info');
}
public function retriveStates()
{
$this->states = CityName::distinct()->get(['state']);
}
public function retriveCities()
{
$this->cities = CityName::where('state', $this->selectedstate)->get(['city']);
}
public function updatedSkillsQuery()
{
$this->skillResults = $this->skills->where('name', 'like', $this->skillsQuery) ?? collect();
}
public function retriveLanguages()
{
$this->language_names = Language::all();
$this->language_levels = LanguageLevel::all();
}
public function addLanguage()
{
if (count($this->languages) <= 3)
{
array_push($this->languages, ['language_name'=>'', 'language_level'=>'', 'id'=>'']);
}
else
{
$this->sweetAlert('error', 'you only can add 3 languages to your profile.');
}
}
public function getUserLanguages()
{
$this->languages = auth()->user()->userLanguages->toArray();
}
public function removeLanguage($languagePosition, $languageId)
{
if (isset($languageId))
{
if ($languageId == 0)
{
array_splice($this->languages, $languagePosition, 1);
}
else
{
array_push($this->languageToDelete, $languageId);
array_splice($this->languages, $languagePosition, 1);
}
}
}
public function addCertificate()
{
if (count($this->certificates) <= 5)
{
array_push($this->certificates, ['name'=>'', 'school'=>'', 'link'=>'', 'date'=>'', 'id'=>'']);
/* dd($this->languages); */
}
else
{
$this->sweetAlert('error', 'you only can add 5 certificates to your profile.');
}
}
public function mount()
{
$this->skills = collect([
['name' => 'vue'],
['name' => 'vue'],
['name' => 'vue'],
['name' => 'laravel'],
['name' => 'laravel'],
['name' => 'laravel'],
]);
$this->skillResults= [];
$this->skillsQuery = '';
/* $this->retriveLanguages();
$this->retriveStates();
$this->retriveCities(); */
$this->getUserLanguages();
$this->name = auth()->user()->name;
$this->email = auth()->user()->email;
$this->phone = auth()->user()->phone;
$this->selectedstate = auth()->user()->userprofile->state;
$this->selectedcity = auth()->user()->userprofile->city;
$this->jobTitle = auth()->user()->userprofile->job_title;
$this->aboutMe = auth()->user()->userprofile->about_me;
$this->employer = auth()->user()->userprofile->employer;
$this->position = auth()->user()->userprofile->position;
$this->edu_course = auth()->user()->userprofile->edu_course;
$this->edu_school = auth()->user()->userprofile->edu_school;
$this->edu_level = auth()->user()->userprofile->edu_level;
$this->edu_start_date = auth()->user()->userprofile->edu_start_date;
$this->edu_end_date = auth()->user()->userprofile->edu_end_date;
$this->employment_looking = auth()->user()->userprofile->employment_looking;
$this->employment_hired = auth()->user()->userprofile->employment_hired;
$this->twitter = auth()->user()->userprofile->twitter;
$this->linkedin = auth()->user()->userprofile->linkedin;
$this->github = auth()->user()->userprofile->github;
$this->instagram = auth()->user()->userprofile->instagram;
$this->website = auth()->user()->userprofile->website;
}
public function rules()
{
return [
'name' => ['required', 'string', 'max:250'],
'email' => [
'required',
'email',
'max:250',
Rule::unique('users')->ignore(auth()->id()),
],
'phone' => ['required', 'digits:11'],
'selectedstate' => 'required',
'selectedcity' => 'required',
'jobTitle' => ['required', 'string', 'max:250'],
'aboutMe' => ['required', 'string', 'max:250'],
'employer' => ['string', 'max:250'],
'position' => ['string', 'max:250'],
'edu_course' => ['nullable', 'string', 'max:250'],
'edu_school' => ['nullable', 'string', 'max:250'],
'edu_level' => ['nullable', 'string', 'max:250'],
'edu_start_date' => ['nullable', 'string'],
'edu_end_date' => ['nullable', 'string'],
'employment_looking' => ['nullable', 'boolean'],
'employment_hired' => ['nullable', 'boolean'],
'twitter' => ['nullable', 'string', 'max:250'],
'linkedin' => ['nullable', 'string', 'max:250'],
'github' => ['nullable', 'string', 'max:250'],
'instagram' => ['nullable', 'string', 'max:250'],
'website' => ['nullable', 'string', 'max:250'],
'languages.*.language_name' => ['required', 'exists:App\Models\Language,abbreviation'],
'languages.*.language_level' => ['required', 'exists:App\Models\LanguageLevel,level'],
];
}
public function submit()
{
$user = Auth::user();
$this->validate();
User::where('id', auth()->id())->update([
'name' => $this->name,
'email' => $this->email,
'phone' => $this->phone,
]);
UserProfile::where('user_id', auth()->id())->update([
'state' => $this->selectedstate,
'city' => $this->selectedcity,
'job_title' => $this->jobTitle,
'about_me' => $this->aboutMe,
'employer' => $this->employer,
'position' => $this->position,
'edu_course' => $this->edu_course,
'edu_school' => $this->edu_school,
'edu_level' => $this->edu_level,
'edu_start_date' => $this->edu_start_date,
'edu_end_date' => $this->edu_end_date,
'employment_looking' => $this->employment_looking,
'employment_hired' => $this->employment_hired,
'twitter' => $this->twitter,
'linkedin' => $this->linkedin,
'github' => $this->github,
'instagram' => $this->instagram,
'website' => $this->website,
]);
if (!empty($this->languageToDelete))
{
/* $user = Auth::user(); */
foreach ($this->languageToDelete as $delete)
{
$user->userLanguages()->where('id', $delete)->delete();
}
}
foreach ($this->languages as $language)
{
/* $user = Auth::user(); */
$user->userLanguages()->updateOrCreate([
'language_name' => $language['language_name'],
],
[
'language_name' => $language['language_name'],
'language_level' => $language['language_level']
]
);
}
$this->getUserLanguages();
$this->sweetAlert('success', 'changes saved!');
}
public function sweetAlert($type, $message)
{
$this->alert($type, $message, [
'position' => 'bottom-end',
'timer' => 5000,
'toast' => true,
'text' => null,
'showCancelButton' => false,
'showConfirmButton' => false
]);
}
}
Awarded Best Reply on $loop->index Messes Up The Other Foreach
That's a good one. I'm sure there are many ways to improve my code but the problem right now is the disappearance of the language section upon adding a new certificate section.
Replied to $loop->index Messes Up The Other Foreach
That's a good one. I'm sure there are many ways to improve my code but the problem right now is the disappearance of the language section upon adding a new certificate section.
Replied to $loop->index Messes Up The Other Foreach
Sorry for the language barrier. It's Persian by the way. I have added some English labels for those two sections so it may be less confusing and I recorded it again.
https://drive.google.com/file/d/1Hq2wTKcPvhs05SKFMICaRoOAzpSyj9Iz/view?usp=sharing
I understand what are you saying regarding the language and the language level but there are some things that need to mention.
1- changes are not persisted to the DB in real-time and there is a save button at the bottom of the page to persist the changes to the DB.
2- imagine this scenario: I as a user decide to add English and Spanish to my spoken language section. I add the English and the corresponding level of proficiency and then Spanish. then I decide I will not add Spanish to my profile so I decided to remove it. if we go with the delete by ID solution it is not possible to do so since the changes are not persisted in the DB yet therefore there is no ID for the added Spanish language yet because the ID field is auto-generated by the DB. that's why I came up with the array solution to be able to remove the recently added language and not yet saved in DB language.
Replied to $loop->index Messes Up The Other Foreach
the issue is very odd because it seems only the first language will disappear and then after another render it will appear again. I made another screen record to show it. hope it will help. i tried moving things around from calling the functions I was suspected to from mount to render and also tried other lifecycle hooks like hydrate, dehydrate, update, updated
but no luck.
https://drive.google.com/file/d/1lo4FNwHtu56rHQMM-1gQ4nbDnLM-dJLi/view?usp=sharing
Also, something else I noticed is that after adding a new language section or any other sections dynamically the fields that I defined as date fields using flatpickr will not pop the date picker anymore until I refresh the page. not sure what is causing this issue.
Replied to $loop->index Messes Up The Other Foreach
You are absolutely right and that's the path I took at first but the issue was when you add a new language and decide to not save it to the database you won't be able to remove it from the form/view since it doesn't have any id yet and also it is not in the DB yet. so that's why I invented this odd solution.
Regardless I don't think it has something to do with the issue I'm having right now? or does it?
Replied to $loop->index Messes Up The Other Foreach
Here is the livewire component code maybe your eyes will catch something that mine didn't.
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\CityName;
use App\Models\Language;
use App\Models\LanguageLevel;
use App\Models\User;
use App\Models\UserLanguage;
use App\Models\UserProfile;
use Illuminate\Validation\Rule;
use Illuminate\Support\Facades\Auth;
class UserInfo extends Component
{
public $name;
public $email;
public $phone;
public $states = [];
public $selectedstate;
public $cities = [];
public $selectedcity;
public $jobTitle;
public $aboutMe;
public $employer;
public $position;
public $edu_course;
public $edu_school;
public $edu_level;
public $edu_start_date;
public $edu_end_date;
public $employment_looking;
public $employment_hired;
public $twitter;
public $linkedin;
public $github;
public $instagram;
public $website;
public $languages = [];
public $language_names;
public $language_levels;
public $languageToDelete = [];
public $certificates = [];
public $certificate_name;
public $certificate_school;
public $certificate_link;
public $certificate_date;
public $certificateToDelete = [];
public $skillsQuery;
public $skillResults;
public $skills;
public function render()
{
/* $this->retriveStates();
$this->retriveCities();
$this->retriveLanguages(); */
return view('livewire.user-info');
}
public function retriveStates()
{
$this->states = CityName::distinct()->get(['state']);
}
public function retriveCities()
{
$this->cities = CityName::where('state', $this->selectedstate)->get(['city']);
}
public function updatedSkillsQuery()
{
$this->skillResults = $this->skills->where('name', 'like', $this->skillsQuery) ?? collect();
}
public function retriveLanguages()
{
$this->language_names = Language::all();
$this->language_levels = LanguageLevel::all();
}
public function addLanguage()
{
if (count($this->languages) <= 3)
{
array_push($this->languages, ['language_name'=>'', 'language_level'=>'', 'id'=>'']);
}
else
{
$this->sweetAlert('error', 'تنها مجاز به اضافه کردن ۳ زبان به پروفابل خود هستید.');
}
}
public function getUserLanguages()
{
$this->languages = auth()->user()->userLanguages->toArray();
}
public function removeLanguage($languagePosition, $languageId)
{
if (isset($languageId))
{
if ($languageId == 0)
{
array_splice($this->languages, $languagePosition, 1);
}
else
{
array_push($this->languageToDelete, $languageId);
array_splice($this->languages, $languagePosition, 1);
}
}
}
public function addCertificate()
{
if (count($this->certificates) <= 5)
{
array_push($this->certificates, ['name'=>'', 'school'=>'', 'link'=>'', 'date'=>'', 'id'=>'']);
/* dd($this->languages); */
}
else
{
$this->sweetAlert('error', 'تنها مجاز به اضافه کردن ۵ زبان به پروفابل خود هستید.');
}
}
public function mount()
{
$this->skills = collect([
['name' => 'vue'],
['name' => 'vue'],
['name' => 'vue'],
['name' => 'laravel'],
['name' => 'laravel'],
['name' => 'laravel'],
]);
$this->skillResults= [];
$this->skillsQuery = '';
$this->retriveLanguages();
$this->retriveStates();
$this->retriveCities();
$this->getUserLanguages();
$this->name = auth()->user()->name;
$this->email = auth()->user()->email;
$this->phone = auth()->user()->phone;
$this->selectedstate = auth()->user()->userprofile->state;
$this->selectedcity = auth()->user()->userprofile->city;
$this->jobTitle = auth()->user()->userprofile->job_title;
$this->aboutMe = auth()->user()->userprofile->about_me;
$this->employer = auth()->user()->userprofile->employer;
$this->position = auth()->user()->userprofile->position;
$this->edu_course = auth()->user()->userprofile->edu_course;
$this->edu_school = auth()->user()->userprofile->edu_school;
$this->edu_level = auth()->user()->userprofile->edu_level;
$this->edu_start_date = auth()->user()->userprofile->edu_start_date;
$this->edu_end_date = auth()->user()->userprofile->edu_end_date;
$this->employment_looking = auth()->user()->userprofile->employment_looking;
$this->employment_hired = auth()->user()->userprofile->employment_hired;
$this->twitter = auth()->user()->userprofile->twitter;
$this->linkedin = auth()->user()->userprofile->linkedin;
$this->github = auth()->user()->userprofile->github;
$this->instagram = auth()->user()->userprofile->instagram;
$this->website = auth()->user()->userprofile->website;
}
public function rules()
{
return [
'name' => ['required', 'string', 'max:250'],
'email' => [
'required',
'email',
'max:250',
Rule::unique('users')->ignore(auth()->id()),
],
'phone' => ['required', 'digits:11'],
'selectedstate' => 'required',
'selectedcity' => 'required',
'jobTitle' => ['required', 'string', 'max:250'],
'aboutMe' => ['required', 'string', 'max:250'],
'employer' => ['string', 'max:250'],
'position' => ['string', 'max:250'],
'edu_course' => ['nullable', 'string', 'max:250'],
'edu_school' => ['nullable', 'string', 'max:250'],
'edu_level' => ['nullable', 'string', 'max:250'],
'edu_start_date' => ['nullable', 'string'],
'edu_end_date' => ['nullable', 'string'],
'employment_looking' => ['nullable', 'boolean'],
'employment_hired' => ['nullable', 'boolean'],
'twitter' => ['nullable', 'string', 'max:250'],
'linkedin' => ['nullable', 'string', 'max:250'],
'github' => ['nullable', 'string', 'max:250'],
'instagram' => ['nullable', 'string', 'max:250'],
'website' => ['nullable', 'string', 'max:250'],
'languages.*.language_name' => ['required', 'exists:App\Models\Language,abbreviation'],
'languages.*.language_level' => ['required', 'exists:App\Models\LanguageLevel,level'],
];
}
public function submit()
{
$user = Auth::user();
$this->validate();
User::where('id', auth()->id())->update([
'name' => $this->name,
'email' => $this->email,
'phone' => $this->phone,
]);
UserProfile::where('user_id', auth()->id())->update([
'state' => $this->selectedstate,
'city' => $this->selectedcity,
'job_title' => $this->jobTitle,
'about_me' => $this->aboutMe,
'employer' => $this->employer,
'position' => $this->position,
'edu_course' => $this->edu_course,
'edu_school' => $this->edu_school,
'edu_level' => $this->edu_level,
'edu_start_date' => $this->edu_start_date,
'edu_end_date' => $this->edu_end_date,
'employment_looking' => $this->employment_looking,
'employment_hired' => $this->employment_hired,
'twitter' => $this->twitter,
'linkedin' => $this->linkedin,
'github' => $this->github,
'instagram' => $this->instagram,
'website' => $this->website,
]);
if (!empty($this->languageToDelete))
{
/* $user = Auth::user(); */
foreach ($this->languageToDelete as $delete)
{
$user->userLanguages()->where('id', $delete)->delete();
}
}
foreach ($this->languages as $language)
{
/* $user = Auth::user(); */
$user->userLanguages()->updateOrCreate([
'language_name' => $language['language_name'],
],
[
'language_name' => $language['language_name'],
'language_level' => $language['language_level']
]
);
}
$this->getUserLanguages();
$this->sweetAlert('success', 'تغییرات با موفقیت ذخیره شد!');
}
public function sweetAlert($type, $message)
{
$this->alert($type, $message, [
'position' => 'bottom-end',
'timer' => 5000,
'toast' => true,
'text' => null,
'showCancelButton' => false,
'showConfirmButton' => false
]);
}
}
Replied to $loop->index Messes Up The Other Foreach
Yes i did. here is the changed code:
<!-- language section -->
<div class="card card-profile shadow-sm mt-4">
<div class="px-4 mt-4 mb-4">
<div class="h5 font-weight-bold mb-4">زبانهای خارجی</div>
<div class="heading text-muted mb-4">تنها مجاز به اضافه کردن ۳ زبان به پروفابل خود هستید.</div>
@foreach ($languages as $lindex => $language)
<div class="card card-body mb-4" wire:key="{{ $lindex }}">
<div class="text-left"><span class="fa fa-trash text-gray language-delete" wire:click="removeLanguage({{ $lindex }}, {{ !empty($language['id']) ? $language['id'] : 0 }})"></span></div>
<div class="row">
<div class="form-group col-md-6">
<label class="" for="languageName">زبان</label>
<select class="form-control form-control-alternative" name="language-name" {{-- id="languageName" --}} wire:model="languages.{{ $lindex }}.language_name">
<option value="" class="form-control" selected disabled>انتخاب زبان</option>
@foreach ($language_names as $name)
<option value="{{ $name->abbreviation }}" class="form-control">{{ $name->language }}</option>
@endforeach
</select>
</div>
<div class="form-group col-md-6">
<label class="" for="languageProficiency">میزان تسلط</label>
<select class="form-control form-control-alternative" name="language-proficiency" {{-- id="languageProficiency" --}} wire:model="languages.{{ $lindex }}.language_level">
<option value="" class="form-control" selected disabled>میزان تسلط</option>
@foreach ($language_levels as $level)
<option value="{{ $level->level }}" class="form-control">{{ $level->name }}</option>
@endforeach
</select>
</div>
</div>
</div>
@endforeach
@error('languages.*.language_level')
<small class="text-warning">{{ $message }}</small>
@enderror
@error('languages.*.language_language')
<small class="text-warning">{{ $message }}</small>
@enderror
@if (count($languages) < 3)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addLanguage"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
</div>
</div>
<!-- end language section -->
<!-- other certificates section -->
<div class="card card-profile shadow-sm mt-4">
<div class="px-4 mt-4 mb-4">
<div class="h5 font-weight-bold mb-4">دیگر مدارک مرتبط </div>
<div class="heading text-muted mb-4">اگر مدارک دیگری در زمینه کاری خود دارید در زیر وارد کنید.</div>
@foreach ($certificates as $cindex => $certificate)
<div class="card card-body mb-4" wire:key="{{ $cindex }}">
<div class="row">
<div class="form-group col-md-6">
<label class="" for="other-certificates-name">نام مدرک</label>
<input type="text" class="form-control form-control-alternative" placeholder="" name="ptherCertificatesName">
</div>
<div class="form-group col-md-6">
<label class="" for="other-certificates-school-name">نام مرکز آموزشی</label>
<input type="text" class="form-control form-control-alternative" placeholder="" name="otherCertificatesSchoolName">
</div>
<div class="form-group col-md-6">
<label class="" for="other-certificates-verification-link">لینک تایید <small>(اختیاری)</small></label>
<input type="text" class="form-control form-control-alternative text-left" placeholder="" name="otherCertificatesVerificationLink">
</div>
<div class="form-group col" dir="ltr">
<label class="" for="other-certificates-grad-date" dir="rtl">تاریخ اخذ</label>
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-calendar-grid-58"></i></span>
</div>
<input type="text" class="form-control form-control-alternative datePicker" placeholder="" name="otherCertificatesGradDate" value="">
</div>
</div>
</div>
</div>
@endforeach
@if (count($certificates) < 5)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addCertificate"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
</div>
</div>
<!-- end other certificates section -->
perhaps the issue is not what i thought might be.
Replied to $loop->index Messes Up The Other Foreach
I'm completely losing my mind here. after the changes, you mentioned the same issue is still going on. I had to screen record it to show you exactly what is going on.
https://drive.google.com/file/d/1WhzJ2iTRO_2xnmuNkO9fq_J_7Fa4FZDK/view?usp=sharing
Replied to $loop->index Messes Up The Other Foreach
that's what exactly is confusing me because those are two separate loops in a view. it's very odd.
Started a new Conversation $loop->index Messes Up The Other Foreach
I have 2 separate foreach loops in my view which I use $loop->index
for wire:key
value to keep track of the components during adding and deleting them.
when clicking the second button to add the second component it seems the $loop->index
in the second foreach turns the other $loop->index
to zero which is odd since the $loop->index
supposed to return The index of the current loop iteration and not have an effect on the other ones.
any idea whats going on and how can i fix this?
first loop:
@foreach ($languages as $language)
<div class="card card-body mb-4" wire:key="{{ $loop->index }}">
<div class="text-left"><span class="fa fa-trash text-gray language-delete" wire:click="removeLanguage({{ $loop->index }}, {{ !empty($language['id']) ? $language['id'] : 0 }})"></span></div>
<div class="row">
<div class="form-group col-md-6">
<label class="" for="languageName">زبان</label>
<select class="form-control form-control-alternative" name="language-name" {{-- id="languageName" --}} wire:model="languages.{{ $loop->index }}.language_name">
<option value="" class="form-control" selected disabled>انتخاب زبان</option>
@foreach ($language_names as $name)
<option value="{{ $name->abbreviation }}" class="form-control">{{ $name->language }}</option>
@endforeach
</select>
</div>
<div class="form-group col-md-6">
<label class="" for="languageProficiency">میزان تسلط</label>
<select class="form-control form-control-alternative" name="language-proficiency" {{-- id="languageProficiency" --}} wire:model="languages.{{ $loop->index }}.language_level">
<option value="" class="form-control" selected disabled>میزان تسلط</option>
@foreach ($language_levels as $level)
<option value="{{ $level->level }}" class="form-control">{{ $level->name }}</option>
@endforeach
</select>
</div>
</div>
</div>
@endforeach
@error('languages.*.language_level')
<small class="text-warning">{{ $message }}</small>
@enderror
@error('languages.*.language_language')
<small class="text-warning">{{ $message }}</small>
@enderror
@if (count($languages) < 3)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addLanguage"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
2nd loop:
@foreach ($certificates as $certificate)
<div class="card card-body mb-4" wire:key="{{ $loop->index }}">
<div class="row">
<div class="form-group col-md-6">
<label class="" for="other-certificates-name">نام مدرک</label>
<input type="text" class="form-control form-control-alternative" placeholder="" id="other-certificates-name" name="ptherCertificatesName">
</div>
<div class="form-group col-md-6">
<label class="" for="other-certificates-school-name">نام مرکز آموزشی</label>
<input type="text" class="form-control form-control-alternative" placeholder="" id="other-certificates-school-name" name="otherCertificatesSchoolName">
</div>
<div class="form-group col-md-6">
<label class="" for="other-certificates-verification-link">لینک تایید <small>(اختیاری)</small></label>
<input type="text" class="form-control form-control-alternative text-left" placeholder="https://devindex.ir" id="other-certificates-verification-link" name="otherCertificatesVerificationLink">
</div>
<div class="form-group col" dir="ltr">
<label class="" for="other-certificates-grad-date" dir="rtl">تاریخ اخذ</label>
<div class="input-group input-group-alternative">
<div class="input-group-prepend">
<span class="input-group-text"><i class="ni ni-calendar-grid-58"></i></span>
</div>
<input type="text" class="form-control form-control-alternative datePicker" placeholder="" id="other-certificates-grad-date" name="otherCertificatesGradDate" value="">
</div>
</div>
</div>
</div>
@endforeach
@if (count($certificates) < 5)
<div class="row">
<div class="col-md-12">
<button type="button" class="btn btn-outline-secondary btn-round btn-block" wire:click="addCertificate"><span class="btn-inner--icon"><i class="fa fa-plus fa-2x"></i></span></button>
</div>
</div>
@endif
Replied to Livewire Search Drop Down Leaves A Blank When Empty
The error is still the Call to a member function isNotEmpty() on null
. and with a bit of search it turned out For some weird reasons, in views, it sometimes refers to an empty Collection as null
.
My problem? I'm not sure if I'm liking your way of talking. You provided answers which didn't work and then I used an old way of doing it. the whole point was not to use the count()
and was hoping there will be a better and more modern way to do it but it turned out there isn't in this case.
Not sure why are you being rude?
Awarded Best Reply on Livewire Search Drop Down Leaves A Blank When Empty
still the same error. guess ill just go with the count()
instead of !empty()
or isNotEmpty()
.
Replied to Livewire Search Drop Down Leaves A Blank When Empty
still the same error. guess ill just go with the count()
instead of !empty()
or isNotEmpty()
.
Replied to Livewire Search Drop Down Leaves A Blank When Empty
it returns the Call to a member function isNotEmpty() on null
error
Replied to Livewire Search Drop Down Leaves A Blank When Empty
I did what you mentioned but its still the same issue.
and yes $skillResults
is a collection. $this->skillResults = $this->skills->where('name', 'like', $this->skillsQuery);
Started a new Conversation Livewire Search Drop Down Leaves A Blank When Empty
I have a Livewire search dropdown which is supposed to show when there are search results and hide where there is none everything is working fine except the main div
stays blank and visible even if there are no results. the if
is supposed to not show the section if the search result property is empty but can't figure out why it's not working. Worth mentioning that on the page load everything is fine until you start searching.
search view section:
<div class="col-md-12">
@if (!empty($skillResults))
<div class="position-relative">
<div class="bg-secondary text-left p-2 justify-content-end rounded position-absolute w-100 shadow-sm skills-search-dropdown" dir="ltr">
<ul class="mb-0 list-group list-group-flush bg-secondary">
@if ($skillResults->count() > 0)
@foreach ($skillResults as $result)
<li class="list-group-item bg-secondary">{{ $result['name'] }}</li>
@endforeach
@elseif (strlen($skillsQuery) > 0)
<li class="list-group-item bg-secondary text-right" dir="rtl">No results</li>
@endif
</ul>
</div>
</div>
@endif
</div>
Replied to How To Create Collections In Livewire Component?
I'm trying to define a property as a collection and assign its values at the same time like $collection = collect([1, 2, 3]);
which is what I have been doing for a while using regular PHP inside the Laravel controllers if I wanted a collection with static values. but it looks like it's not possible to do the same in Livewire and instead I have to define a property like public $collection;
and then use a method to assign its values.
My pint is why does someone need to do all the extra work just to define a collection with static properties?
Replied to How To Create Collections In Livewire Component?
Right and $collection = collect([1, 2, 3]);
does declare the property as a collection and give its values as the same time. so why the same thing is not possible in Livewire without declaring the property first and then use a method to assign it as a collection and give its values?