foreach loop for two variables in laravel - variables

below is my codes in controller and php file. How do I run the foreach for both $posts and $users? I have tried #foreach(array_merge($posts,$users) as $post) but doesn't work.
WelcomeController:
public function index()
{
$posts = Post::all();
$users = User::all();
return view('welcome', [
'posts' => $posts,
'users' => $users
]);
}
blade.php:
#foreach($posts as $post)
<div class="column">
<div class="content">
<img src="/storage/{{$post->image}}" style="width:100%" id="myImg">
<h4>By {{$user->name}}</h4>
<p>{{$post->caption}}</p>
<p class="description">{{$post->description}}</p>
</div>
</div>
#endforeach

I suggest you to use one to many (inverse) relationship visit
In post model add:
public function user()
{
return $this->belongsTo('App\Models\User');
}
And in blade.php:
{{ $post->user->name }}

Related

Autocomplete cannot search in table with two foreign key Laravel

and i want make autosearch from local database, but in other case with table in detail cannot be get, but in just manual search is successfully:
Image of table with two foreign key
code in my controller for method index is (this is just manual search) :
public function index(Request $request)
{
$filterKeyword = $request->get('keyword');
$data['course'] = Course::paginate(5);
if ($filterKeyword) {
$data['course'] = Course::where('title', 'LIKE', "%$filterKeyword%")->paginate(5);
}
return view('course.index', $data);
}
code in my routes/web is
Route::get('course.search', function (Request $request) {
$query = $request->get('query');
$filterResult = Course::where('title', 'LIKE', '%' . $query . '%')->get();
return response()->json($filterResult);
});
my code in view(interface) is :
<div class="col-8">
<input type="search" class="typeahead form-control" value="{{ Request::get('keyword') }}"id="keyword" name="keyword">
</div>
<div class="col-2">
<button type="submit" class="btn btn-outline-info"><span class="fas fa-search"></span></button>
</div>
my javascript for get query when input :
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-3-typeahead/4.0.2/bootstrap3-typeahead.min.js"></script>
<script type="text/javascript">
var route = "{{ url('course.search') }}";
$('#keyword').typeahead({
source: function(query, process) {
return $.get(route, {
query: query
}, function(data) {
return process(data);
});
}
});
</script>
is there a certain way to anticipate from foreign field?

Vue.js Autocomplete

I am building a live search component with Vuejs. The search is working as expected. On keyup the method populates an unordered list. I am at a loss but need to:
Click on a selection from the search results and populate the input with that name.
Get the selected id.
Any suggestions?
The View
<label>Vendor:</label>
<input type="text" v-model="vendor" v-on:keyup="get_vendors">
<div class="panel-footer" v-if="vendors.length">
<ul class="list-group">
<li class="list-group-item for="vendor in vendors">
{{ vendor.vendor_name }}
</li>
</ul>
</div>
The Script
export default {
data: function() {
return {
vendor:'',
vendors: []
}
},
methods: {
get_vendors(){
this.vendors = [];
if(this.vendor.length > 0){
axios.get('search_vendors',{params: {vendor: this.vendor}}).then(response =>
{
this.vendors = response.data;
});
}
}
}
}
</script>
The Route
Route::get('search_vendors', 'vendorController#search_vendors');
The Controller
public function search_vendors(Request $request){
$vendors = vendor::where('vendor_name','LIKE','%'.$request->vendor.'%')->get();
return response()->json($vendors);
}
This is what I came up with. Works nicely.
The View
<label>Vendor:</label>
<input type="text" v-model="vendor" v-on:keyup="get_vendors" class="col-xl-6 form-control ">
<div class="panel-footer autocomplete-box col-xl-6">
<ul class="list-group">
<li v-for="(vendor,id) in vendors" #click="select_vendor(vendor)" class="list-group-item autocomplete-box-li">
{{ vendor.vendor_name }}
</li>
</ul>
</div>
The Script
export default {
data: function() {
return {
vendor:'',
vendor_id:'',
vendors: []
}
},
methods: {
select_vendor(vendor){
this.vendor = vendor.vendor_name
this.vendor_id = vendor.id
this.vendors = [];
},
get_vendors(){
if(this.vendor.length == 0){
this.vendors = [];
}
if(this.vendor.length > 0){
axios.get('search_vendors',{params: {vendor: this.vendor}}).then(response => {
this.vendors = response.data;
});
}
},
},
}
</script>
The Route
Route::get('search_vendors', 'vendorController#search_vendors');
The Controller
public function search_vendors(Request $request){
$vendors = vendor::where('vendor_name','LIKE','%'.$request->vendor.'%')->get();
return response()->json($vendors);
}
The CSS
.autocomplete-box-li:hover {
background-color: #f2f2f2;
}
.autocomplete-box{
position: absolute;
z-index: 1;
}
If you want to get the id of the vendor you can do it using vendor.vendor_id which should be present in the vendor object which is returned from the server and if you want to populate the vendors array with new options you can have a watch or a #change (binding) function to add the entered text field as the new vendor in the vendor array. Also, I would suggest that you download the vue extension as it will help you a lot in debugging
<label>Vendor:</label>
<input type="text" v-model="vendor" v-on:keyup="get_vendors">
<div class="panel-footer" v-if="vendors.length">
<ul class="list-group">
<li class="list-group-item for="(vendor,index) in vendors">
{{ index }}
{{ vendor.vendor_id }}
{{ vendor.vendor_name }}
</li>
</ul>
</div>

Laravel - dropbox driver - This driver does not support retrieving URLs

Using
Laravel 5.7
I'm trying to use dropbox driver to upload images , it works .. but when i want to get the url .. it gives me an error
This driver does not support retrieving URLs
filesystems.php
'disks' => [
'dropbox' => [
'driver' => 'dropbox',
'app_secret' => env('DROPBOX_APP_SECRET'),
'token' => env('DROPBOX_TOKEN'),
],
],
UploadController.php
public function postUpload(Request $request)
{
$user = Auth::user();
$file = $request->file('picture');
$filename=uniqid($user->id."_").".".$file->getClientOriginalExtension();
Storage::disk('dropbox')->put($filename, File::get($file), 'public');
$url = Storage::disk('dropbox')->url($filename);
$user->profile_pic = $url;
$user->save();
$user->profile_pic = $filename;
$user->save();
return view('upload-complete')->with('filename', $filename)->with('url',$url);
}
upload-complete.blade.php
#extends('template')
#section('content')
<div class="container">
<h1>File Uploaded</h1>
<hr />
<div class="text-center">
<img src="{{ $url }}" class="img-rounded" />
</div>
</div>
#endsection

why delete failed to removed the record?

i have the following action for the delete operation:
[HttpPost]
public ActionResult Delete(int id, EmployeeDeleteViewModel collection)
{
try
{
if (ModelState.IsValid)
{
Employee e = new Employee
{
EmpId = collection.EmpID,
FirstName = collection.FirstName,
LastName = collection.LastName,
DepartmentId = collection.DepartmentID
};
db.Employees.Remove(e);
db.SaveChanges();
return RedirectToAction("Index", new { id = id });
}
// TODO: Add update logic here
return View(collection);
}
catch
{
return View();
}
}
the delete view is:
#model VirtualCampus2.Models.EmployeeDeleteViewModel
#{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<fieldset>
<legend>EmployeeDeleteViewModel</legend>
<div class="display-label">
#Html.DisplayNameFor(model => model.EmpID)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.EmpID)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.FirstName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.FirstName)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.LastName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.LastName)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.DepartmentName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.DepartmentName)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.DepartmentID)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.DepartmentID)
</div>
</fieldset>
#using (Html.BeginForm())
{
<p>
<input type="submit" value="Delete" /> |
#Html.ActionLink("Back to List", "Index")
</p>
}
When i click delete on the delete view the following error occurs:
to action method's second parameter "collection", it sends a collection with zeros and null in their properties
does not delete the record
Here is video that shows the problem
why this happens and how do i fix this?
To Steve:
I have made the changes by creating a separate view model and a delete action:
ViewModel:
public class EmpDeleteCommitViewModel
{
public int EmpID { get; set; }
}
the actions Delete methods:
[HttpGet]//this works fine, gets the record to show on view
public ActionResult Delete(int id)
{
var empList = db.Employees.ToList();
var employee = empList.Where(e => e.EmpId == id).Select(e => new EmployeeDeleteViewModel
{
EmpID=e.EmpId,
FirstName= e.FirstName,
LastName=e.LastName,
DepartmentID=e.DepartmentId,
DepartmentName=e.Department.Name
}).FirstOrDefault();
return View(employee);
}
[HttpPost] //BUT THIS DOES NOT WORK!, evm EmpID does not contain id value
public ActionResult Delete(EmpDeleteCommitViewModel evm)
{
try
{
var employee = db.Employees.Where(e => e.EmpId == evm.EmpID).FirstOrDefault();
db.Employees.Remove(employee);
db.SaveChanges();
return RedirectToAction("Index", new { id = evm.EmpID });
}
catch
{
return View();
}
}
You have no form controls (<input>) between form tags so there is nothing to post back when you submit the form. All you doing is generating some text to display the property values.
There is no need to include the EmployeeDeleteViewModel collection parameter in you method. Your int id parameter will be bound with the id of the employee assuming your using the correct routing, so all you need to to get the original data model from the database based on the id and then delete it.

ListBoxFor is not fully updating the viewmodel on submit

I have been able to create viewmodel like this (please ignore that it includes another viewmodel, that will be fixed after I solve my current problem :) ):
public class UserViewModel
{
#region Variables
private SecUserViewModel user;
private string[] assignedRolesIds;
private List<SecRoleViewModel> availableRoles;
#endregion
#region Properties
public SecUserViewModel User
{
get { return this.user; }
set { this.user = value; }
}
public string Guid
{
get { return this.user.Guid.ToString(); }
set { this.user.Guid = value; }
}
public string UserName
{
get { return this.user.UserName; }
set { this.user.UserName = value; }
}
public string Email
{
get { return this.user.Email; }
set { this.user.Email = value; }
}
public byte[] AuthDigest
{
get { return this.user.AuthDigest; }
set { this.user.AuthDigest = value; }
}
public bool IsUsingTempPasswd
{
get { return this.user.IsUsingTempPasswd; }
set { this.user.IsUsingTempPasswd = value; }
}
public DateTime? LastLogin
{
get { return this.user.LastLogin; }
set { this.user.LastLogin = value; }
}
public DateTime? PasswordChanged
{
get { return this.user.PasswordChanged; }
set { this.user.PasswordChanged = value; }
}
public string[] AssignedRolesIds
{
get { return this.assignedRolesIds; }
set { this.assignedRolesIds = value; }
}
public List<SecRoleViewModel> AvailableRoles
{
get { return this.availableRoles; }
set { this.availableRoles = value; }
}
#endregion
#region Constructor
public UserViewModel()
{
User = new SecUserViewModel();
AssignedRolesIds = null;
AvailableRoles = new List<SecRoleViewModel>(0);
}
public UserViewModel(SecUserViewModel secUser, List<SecRoleViewModel> roleList, List<SecRoleViewModel> availableList)
{
User = secUser;
AssignedRolesIds = roleList.Select(r => r.Role.Guid.ToString()).ToArray();
AvailableRoles = availableList;
}
#endregion
}
My controller has an edit action. On "GET" I pass viewmodel and it is displayed properly including the multiselect list and preselected values. But when I "POST" the "Edit", UserViewModel that is passed back has "AssignedRolesIds" and "AvailableRoles" Empty, although everything else is filled. When I check FormCollection object, there are "AssignedRolesIds" present as a key.
My view looks like this:
#model DocuLive.ViewModels.UserViewModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_AdminPage.cshtml";
}
<h2>Edit</h2>
<div class="error-message">#TempData["Fail"]</div>
<div class="success-message">#TempData["Success"]</div>
#using (Html.BeginForm("Edit", "User", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>SecUser</legend>
<div class="editor-label">
#Html.LabelFor(model => model.User.Guid)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.Guid)
#Html.HiddenFor(model => model.User.Guid)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.UserName)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.UserName)
#Html.HiddenFor(model => model.User.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.User.Email)
#Html.ValidationMessageFor(model => model.User.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.IsUsingTempPasswd)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.User.IsUsingTempPasswd)
#Html.ValidationMessageFor(model => model.User.IsUsingTempPasswd)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.LastLogin)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.LastLogin)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.User.PasswordChanged)
</div>
<div class="editor-field">
#Html.DisplayFor(model => model.User.PasswordChanged)
</div>
<div class="hidden-field">
#Html.HiddenFor(model => model.User.AuthDigest)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.AssignedRolesIds)
</div>
<div class="editor-field">
#Html.ListBoxFor(x => x.AssignedRolesIds, new MultiSelectList(Model.AvailableRoles, "Guid", "RoleName"), new { Multiple = "multiple", #class = "multi-select-list" })
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Users")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Can anyone advise why only values related to ListBoxFor are not passed back (there is a null value)?
Thanks in advance
It seems that the problem is binding the string array values to string id value of complex object (in my case Role) - but I figured out a way around it eventually. The trick is to have this signature of the method:
[HttpPost]
public ActionResult Edit(UserViewModel user, string [] assignedRolesIds)
And then you have this in view:
#Html.ListBox("AssignedRolesIds",new MultiSelectList(Model.AvailableRoles, "Guid", "RoleName"),new { Multiple = "multiple", #class = "multi-select-list"})
With this solution, you have to reassign "assignedRolesIds" back to "AssignedRolesIds" property on UserViewModel, but that is only two lines (including check that the array is not emppty or null).