Totally new to using reactJS with laravel inertia.
I am trying to render the data from my database to the front end. I use a controller to get the data from the database by using...
// Show all main categories
public static function index() {
return MainCategory::all(['main_category_id', 'main_category_name']);
}
then passing it to the frontend using the web.php by using the following code.
Route::get('/', function () {
return Inertia::render('Admin/Categories', [
'categories' => MainCategoryController::index()
]);
})->name('admin.category-setup');
I currently do not know how to call categories in the front end using reactjs.
How can I do that?
I sometimes approach the accessing of passed props by using Inertia's inbuilt usePage-Hook for React. This comes in handy when you are working with shared data that you have made accessible for all of the frontend components (https://inertiajs.com/shared-data). As long as your Backend (Laravel) Code works properly and the actual categories-Property is handed over to the Categories-Component or shared for all of the frontend, you could do something like this:
import React from 'react';
import { usePage } from '#inertiajs/inertia-react';
function App() {
const categories = usePage().props.categories;
return (
<ul>
{categories.map((category) =>
(<li>{category}</li>))}
</ul>
);
}
The most common practice for me however is to simply give the same variable names that you pass in Laravel into the Inertia-Component into the React-Component-Props like this. To me it looks like that should perfectly work with your Use-Case:
import React from 'react';
function App({categories}) {
return (
<ul>
{categories.map((category) =>
(<li>{category}</li>))}
</ul>
);
}
If you want to find more about Inertia, I highly recommend to go through the docs. The developers did a great job in explaining everything so that an unexperienced Laravel and React Dev could understand what is going on. It is actually not much to read but shows some interesting features:
https://inertiajs.com/
Related
This may be a dumb question, but I've started exploring Laravel Breeze with vue and I'm not sure how to manage resources and their views. (Using Laravel 9)
For example, if I have a table 'members' and a resource controller 'MemberController', ordinarily in the web.php file I would do something like:
Route::resource('members', MemberController::class)->names('members');
Then I'd create a 'member' folder in my resource/views folder to store the views for that table. I could then call the view from the MemberController something like:
public function index()
{
$members = Member::all();
return view('member.index', compact('members'));
}
I'm trying to do something similar using vue in breeze, so I guess I'd have the vue pages in the 'resources/js/Pages' folder. But this didn't seem to work properly.
I don't know how to transition from the previous approach of handling resources and views to Breeze using vue.
What's the recommended way to handle resources in an SPA with Breeze/vue?
After following Djave's suggestion, I took a look at the sample app from inertia.js and that answered everything.
The problem I had was due to using the dot notation when specifying the path to the vue page. So, in my example above, it should instead be like this:
return view('Member/Index', compact('members'));
The inertia sample app code has a lot of good examples!
I'm still a bit new to Vue.js, so I may be fundamentally misunderstanding something about the reactivity of it, but basically, I want to pass some data from PHP Laravel to a Vue.js component and have the Vue.js component automatically update when that data changes.
I've seen several similar posts on SO suggest that I use props to pass the data from a Laravel Blade template to a Vue.js component. Here's an example:
How to pass a PHP variable to Vue component instance in Laravel blade?
I have this working perfectly fine, but now I'm stuck with how to get the component to update when the data dynamically changes after page-load.
Specifically, I have a report table on a particular web page, and when the user clicks certain buttons, etc., I use Ajax to call a Laravel controller action that re-runs a query in my Laravel model to get the new data for the report.
I have the data in a PHP array / JSON, and that data is being properly returned to the client-side and I have access to it in the JS, but now, what do I need to do to force the report component in Vue.js to essentially re-render based on the data I just received? Is there a way to "update props" so that Vue.js detects the change and automatically re-renders the whole report component for me?
This is where I'm stuck, and after quite a bit of research, I can't find how to do this. Thank you.
Are you using Ajax outside of the Vue component? or within it as a method?
I have an example of how I dynamically update the Vue data from within the component itself. I'm not sure how to have external JS update the Vue component directly but I feel this is a good option to look at. I'm using axios instead of Ajax but the principle is the same (Axios is included by default in most Laravel installs past 5.5).
<template>
<div>
<div id="reports">
<!-- Display data -->
{{ reports }}
</div>
<button #click="refreshReports">Refresh</button>
</div>
</template>
<script>
export default {
data() {
return {
endpoint: '/api/MY_ROUTE/'
};
},
props: {
reports: Object
},
methods: {
// Make Axios call to API endpoint
refreshReports() {
// GET version
axios.get(this.endpoint)
.then(({data}) => {
this.reports = data.data;
});
// POST version
axios.post(this.endpoint, {
KEY: 'VALUE',
}).then(({data}) => {
this.reports = data.data;
});
/*
`data.data` assumes the returned response is a JSON Resource
if it's not returning the correct data, put a `console.log(data)` and see how it's getting returned!
*/
}
}
};
</script>
Where in your routes/api.php file you have a route like this:
// GET version
Route::get('MY_ROUTE', 'ReportController#getReports');
// POST version
Route::post('MY_ROUTE', 'ReportController#getReports');
And your Controller would have some method like this:
// app/Http/Controllers/ReportController
public function getReports(Request $request) {
return Reports::all();
}
Does that make sense?
Update:
I'm not sure how to have external JS update the Vue component directly
I know you can import external JS scripts and use their functions in methods but I've never done it that way before.
Something like:
<script>
import { myFunction } from '../external.js'
export default {
methods: {
refreshReports() {
// I have no idea if this is the correct way to do it, just a guess!
this.reports = myFunction();
}
}
};
</script>
I am using Voyager for a basic BREAD admin to a small web application I am building for a small non-profit. Yearly they need to import 300-500 new semi-complex entries into the database from Excel, so I want to build an admin script that will store all the data in the right places automatically.
Is there a structured way to add a custom controller/view to Voyager?
(I have not found such documentation yet, maybe I am blind. So I have started manually extending existing bits of Voyager, but as I get deeper I want to make sure this is the best option for future growth.)
Yes, You can add custom controllers to voyager.
First let's make a controller: php artisan make:controller ExportController
//app/Http/Controllers/ExportController.php
class ExportController extends Controller{
public function form(){
return view('export.form');
}
public function submit(){
// do export stuff
}
}
Add two routes as below:
//routes/web.php
Route::group(['prefix' => 'admin','as' => 'voyager.', 'middleware' => 'admin.user'], function()
{
Route::get('export','ExportController#form')->name('export.form');
Route::post('export','ExportController#submit')->name('export.submit');
});
then make the related view file at resources/views/export/form.blade.php just note you need to #extends('voyager::master')
make a new menu item using Voyager's menu builder
you must use this package. here you can know how to import excel or csv file into database table and export or download in different format using maatwebsite package with the power of PHPOffice's PHPExcel.
and here is video.
I have 5 controllers and 5 models and they are all related to backend. I can easily output data in the backend but I need to that for the frontend as well. Not all of course but some of them.
For example I have controller called BooksController:
public function getBooks(Request $request)
{
$books = Books::all();
return view('backend.books.show', compact('images'));
}
So this will show it in backend without any problems but what I want is for example to loop through all the books and show their images in welcome.blade.php which doesn't have controller.
And also to pass other parameters to that same view from different controllers.
Is this is possible?
Thank you.
You are having an error because you did not declare the variable $image
public function getBooks(Request $request)
{
$books = Books::all();
$images = array_map(function($book) {
$book->image;
}, $books);
return view('backend.books.show', compact('images'));
}
It sounds like you are potentially caught up on some terminology. In this case, it sounds like backend is referring to your admin-facing interface, and frontend is referring to your user-facing interface.
You also seem to be locked on the idea of controllers. Unless the route is verrrrrry basic, create a controller for it.
Have a controller for your welcome view, for your admin view, basically (with some exceptions) a controller per resource or view is fine.
In this case, you would have one controller for your admin book view, and a seperate controller for your welcome view. Both of which would pull the books out of the db and render them in their own way
Is it generally a good idea to interact with database in view layer in MVC frameworks?
I'm using Laravel 4.
I want to show some data from database at top of all website's pages.
I have a main.blade.php and: #include("inc.header")
If I should, how can I connect to database from inc/header.php in right way?
I don't want make multiple connections one here at header.php and one in my pages controllers.
I'm more familiar with PDO than Laravel's database methods and ORMs.
Any advice is appreciated!
Edit
Friends gave nice advice and answers about MVC and Laravel workflow, but my main concern is still here.
Ok I have used controllers and models to get required data, then as I said, it should be present for the view layer in every page, So should I repeat the same task to get the same data in All my controllers' actions? (I guess that's why we have Filters here! then again, is it ok to use db in Laravel filters? using a model?)
Thanks in advance :)
Never do anything more than loop thru your data in your view layer. Basically a normal MVC pattern in laravel could be something like this:
It all begins with the routing layer (which btw. is fantastic in laravel)
Using closures
Route::get('/home', function()
{
//Here data is an array, normally you would fetch data
//from your database here and pass it to the View.
$data = array('this', 'is', 'my', 'data-array');
return View::make('my.view')->with(compact('data');
});
Using controllers (and a controller method)
//the same route is bound to a controller method
Route::get('/home','HomeController#myFunction');
The controller for the above could look something like this:
<?php
class HomeController extends BaseController {
//The function you call from your route
public function myFunction()
{
$data = array('this', 'is', 'my', 'data-array');
return View::make('my.view')->with(compact('data');
}
}
The above example just shows the VC in MVC, but generally you pass data from your models in the same way.
Heres a quick one:
Model usage in controllers
public function myFunction($user)
{
$userdata = User::find($user)->orderBy('firstname', 'desc');
$infodata = Event::find(1)->course;
return View::make('my.view')->with(compact('data', 'infodata');
}
So the idea is that laravel lets you do things in multiple ways. If you have a minor app, and are sure that you can manage without controllers you could skip the controller and keep everything in your routing layer.
For most apps however the controllers are needed for controlling the dataflow in the application.
If you are totally new to MVC you should check out some tuts on the subject.
EDIT:
Ahaa! So you wanted to share some piece of data in all your views! Well thats simple. Because all your controllers extend the BaseController you can simply pass in the data in there. Like so:
class BaseController extends Controller {
public function __construct()
{
$data = array('alot', 'of', 'data');
return View::share('data', $data);
}
}
Now the data variable is available in all the views.
PS. Filters are meant to filter stuff, like to check if certain things are "ok". This could include to check authed users, or form submissions etc.
There is another solution that is especially handy for cases like yours. If you have 15 routes that all ultimately include the inc.header view... well you can see where this is going. You'll have data logic repeated in several places. Patrik suggested using the BaseController which is a good solution but I prefer to use a composer.
View::composer('inc.header', function ($view)
{
$view->some_data = MyModel::where(...)->get();
});
It doesn't get much easier then that. :)
Is it generally a good idea to interact with database in view layer in MVC frameworks?
No, you don't interact with your database (model) in your view layer. MVC stands for "Model View Controller" to separate logic, application data and business rules of your application.
If I should, how can I connect to database from inc/header.php in right way?
I don't want make multiple connections one here at header.php and one in my pages controllers.
You could create a main layout (containing your header) and use this layout for all the pages of your application:
app/views/
layouts/main.blade.php
page1.blade.php
layouts/main.blade.php:
<html>
<head>...</head>
<body>
<div>Your header that will be included in each of your pages</div>
<!-- The content of the current page: -->
#yield('body')
</body>
</html>
page1.blade.php:
#extends('layouts.main')
#section('body')
<div>The content of your page</div>
#stop
Learn more about the Blade templating engine.
Now where do you fetch your data?
The fastest/easiest way to develop is to use the routes as Controllers and as your application evolves you start refactoring your code and create Controllers.
app/routes.php:
Route::get('page1', function(){
//Fetch your data the way you prefer: SQL, Fluent or Eloquent (Laravel ORM)
//$data = DB::select('select * from yourtable');
$data = YourModel::all();
//Pass your data to the view
return View::make('page1')
->with('data', $data);
});
The data can be fetch using Fluent class or Eloquent ORM.
I suggest you to learn the basics of Laravel to properly create the base of your application so it will be really easy to maintain in the future.
The answer and issue here is not so simple. First have just been introduced to MVC and trying to understand the basic concept, the flow for MVC is Controller->Model->View. Here we see that the data is passed from the model directly to the View. The current examples of how to use Laravel MVC is to have the Model return data to controller making the flow as follows: Conntroller->Model-Controller->View. Here we see that the model and view are not aware of each other. A qucik look on wikipedia show that this type of modeling and controlling is know has MVA. The A is for adapter and also known as mediating controller, so now we are back to the answer here. Should we be using MVA or MVC? How would one achieve true MVC in Laravel? Answer is to use {{Form:model}} facade for true MVC. But then what happens if the view changes? should we be calling model from the view to get the new data? Answer is no, if the view has to change then user should have caused a controller to react kicking off a new cycle of MVC. So what we can see here a mix of MVC and MVA using the Laravel framework, can achieve a highly customized flow based on the needs of the site.