I have a problem with Laravel/Inertia which gets me the error message :
Cannot read properties of null (reading 'allowRecurse')
There is a form, i post the form to a controller and after saving the data i tried to redirect to the main page. I tried several ways, return Redirect::route('home'); or return redirect()->back(); even other ways i found searching for a solution. They all give me the same error message.
The redirect()->back() function works and brings me back to my form, but when i try to redirect there i get that same message.
I deleted everything of what i think is not essential, so the form and controller now don't do anything anymore, but still i get that error message.
I can't find anything about this error on the internet. What mistake am I overlooking?
Edit: I found something... Somewhere in page that i am going to (that home.vue page) i have a link with the same URL as where i came from. Apparently Vue or Laravel doesn't approve. But i need that. Can i set the value of AllowRecurse to True somewhere? Or is that a bad idea?
My vue-file:
<template>
<div>
<form #submit.prevent="submit">
<div class="flex justify-center mt-4">
<app-button class="w-1/2 justify-center" :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
Insturen
</app-button>
</div>
</form>
</div>
</template>
<script>
import AppButton from '#/Components/Button.vue'
export default {
components: {
AppButton,
},
props: {
game_id: String,
code: String,
},
data() {
return {
form: this.$inertia.form({
name: '',
email: '',
})
}
},
setup() {
},
methods: {
submit() {
this.form.post(route('toto_store',{'game_id': this.game_id, 'code': this.code}), {
preserveScroll: true,
resetOnSuccess: false,
onSuccess: () => { this.$inertia.visit(route('home'))} ,
});
}
}
}
</script>
My controller:
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Models\Guess;
use Illuminate\Http\Request;
class TotoController extends Controller
{
public function store(Request $request, $id, $code)
{
return redirect()->back()->with("success", "Opgeslagen");
}
}
My webroutes:
Route::get('/', [HomeController::class, 'show'])->name('home');
Route::get('/guesses/{game_id?}', [GuessController::class, 'index'])->name('guesses');
Route::get('/toto/{game_id}/{code}', [TotoController::class, 'create'])->name('toto_create');
Route::post('/toto/{game_id}/{code}', [TotoController::class, 'store'])->name('toto_store');
Route::get('/qr-code/{id}', [QRController::class, 'show'])->name('qr-code');
The error:
Any ideas?
Related
I am working with Laravel and Inertia+Vue.js.
I am trying to delete a row but I get a 405 error method not allowed.
Here is my code in Layout.vue :
<a #click="destroy(website)">delete</a>
import AppLayout from '#/Layouts/AppLayout.vue';
import {Link} from "#inertiajs/inertia-vue3";
import {Inertia} from "#inertiajs/inertia";
export default {
components: {
Link, AppLayout, Inertia
},
props: {
websites: Object
},
methods: {
destroy(website) {
if(confirm('are u sure?')) {
this.$inertia.delete(`/destroy/website/${website.id}`)
}
}
},
the method in my controller :
public function destroy(Website $website)
{
$website->delete();
return redirect()->route('dashboard');
}
my route in web.php :
Route::delete('/destroy/website/{id}', [WebsiteController::class, 'destroy']);
the request from the browser as it appears in the network panel is DELETE https://website.fr/destroy/website/2 (2 is the id of the website I clicked on)
any help will appreciated !
For this to work:
destroy(Website $website)
your route should be:
Route::delete('/destroy/website/{website}', [WebsiteController::class, 'destroy']);
not /destroy/website/{id} so Laravel can inject the model with the id passed from your front end
My suggested code for the routes section:
Route::delete('destroy-website/{website}', [WebsiteController::class, 'destroy']);
I want to test the response in the console log. I am using the google inspect tool. I can't see any response in Network>>XHR. But I have seen that "Form submission canceled because the form is not connected" in console. The sample screen inspect tool screen I can't trace the problem actually where. I am following a course video about laravel and vue. Thanks in advance for your time.
Form
<form v-if="editing" #submit.prevent="update">
<div class="form-group">
<textarea rows="10" v-model="body" class="form-control"></textarea>
</div>
<button #click="editing = false">Update</button>
<button #click="editing = false">Cancel</button>
</form>
in Controller
if ($request->expectsJson()) {
return response()->json([
'message' => 'Answer updated!',
'body_html'
]);
}
Vue.JS
<script>
export default {
props: ['answer'],
data () {
return {
editing: false,
body: this.answer.body,
bodyHtml: this.answer.body_html,
id: this.answer.id,
questionId: this.answer.question_id
}
},
methods: {
update () {
axios.patch(`/questions/${this.questionId}/answers/${this.id}`, {
body: this.body
})
.then(res => {
console.log(res);
this.editing = false;
})
.catch(err => {
console.log("something went wrong");
});
}
}
}
</script>
The form is by default hidden. It appears only when clicking on the Edit button. The only problem is to submit the form. ErrorMessage: Form submission canceled because the form is not connected
You have v-if="editing" in your form set to false. It should be true, because form has to exist on submit. You are removing your form from DOM. Also move this.editing to finally() block in axios call.
As the title states, I'm a little confused how I would tackle a method in my Vue Component with if/else statement based on if the user is logged in and authenticated with Laravel's Auth facade. I'm making various Axios requests which I need to allow/disallow based on if user logged in.
I have VUEX setup and was thinking that I can use local storage somehow to have a state for isLoggedin for example that works with Laravel. But I don't know if this is correct method, or secure and presumably Laravel is already storing it's authentication. So can I just access that direct in Vue?
Some unclean solutions here that I don't think are the best -
https://laracasts.com/discuss/channels/vue/hide-button-if-user-is-logged-with-laravel-and-vuejs
I can not find any examples for this :(
Usually from your controller, you pass the authenticated user object into the view which will then be stored in a javascript variable
Controller:
public function index()
{
return view('index', [
'auth_user' => Auth::user()
]);
}
You will know if a user is authenticated if it returns an object or null where null means no user is authenticated.
In your blade, assign the auth_user into a javascript variable:
<script>
window.auth_user = {!! json_encode($auth_user); !!};
</script>
your vuex store object should atleast look like this:
{
state: {
user: null
},
mutations: {
setAuthUser(state, user) {
state.user = user;
}
},
getters: {
isLoggedIn(state) {
return state.user !== null;
}
}
}
Then in your Vue root component, get the auth_user and save it into the store:
<script>
export default {
mounted() {
this.$store.commit('setAuthUser', window.auth_user);
}
}
</script>
You now basically have a getter called this.$store.getters.isLoggedIn that you can use in your application for checking if a user is currently logged in.
e.g:
Use axios interceptors. You intercept the access denied http response code and then act accordingly.
window.axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
if (419 === error.response.status) {
location.reload();
} else {
//Something else you want to do or do nothing
}
});
Putting a script within blade file will throw Vue Warning. Let me answer "How to check in a Vue component if a user is authenticated in Laravel" and leave you with your Vuex complexity. Also this method is simpler.
So, in your controller:
public function index()
{
return view('index')->with('auth_user', auth()->user());
}
In your blade(main.blade.php):
<div class="container">
<example-component :auth_user='#json($auth_user)'></example-component>
</div>
In your vue-component, get your props(ExampleComponent.vue):
<script>
export default {
props: ['auth_user'],
created () {
console.log(this.auth_user)
}
}
</script>
Returns null if user is not logged in
I'm working with laravel 7+
and it doesn't need to send Auth::user() via controller
Just call it from your laravel blade template file like below
your-template-name.blade.php
#if (Auth::check())
<script>window.authUser={!! json_encode(Auth::user()); !!};</script>
#else
<script>window.authUser=null;</script>
#endif
inside YourComponent.vue, store authUser like this:
<script>
export default {
data() {
return {
authUser: window.authUser
}
},
created() {
console.log(this.authUser);
},
methods: {
yourMethodName() {
console.log(this.authUser);
}
}
}
<script>
I'm using laravel 5.6 as the api for the backend and vuejs for the frontend spa application. And https://github.com/nicolaslopezj/searchable package for search which worked well in my previous projects where i used blade templating engine.
I'm new to vuejs and im learning how to do things and im stuck at a point where im confused how to use laravel search on the frontend.
What i did previously in other projects where i used blade for the frontend
In my controller
public function index(Request $request)
{
$start_search = microtime('s');
$searchterm = $request->input('search');
if($request->has('search')){
$results = Web::search($searchterm)->paginate(10);
} else {
$results = Web::latest()->paginate(10);
}
$stop_search = microtime('s');
$time_search = ($stop_search - $start_search);
return view('search.index', compact('results', 'searchterm', 'time_search'));
}
And in my view
<small>{{$results->total()}} results found for "<em class="b-b b-warning">{{$searchterm}}</em>" in {{$time_search}} seconds</small>
#forelse ($results as $result)
<div class="mb-3">
{{$result->meta_title}} <span class="badge badge-pill primary">{{$result->rank}}</span>
<span class="text-success clear h-1x">{{$result->url}}</span>
<span class="h-2x">{{$result->meta_description}}</span>
</div>
#empty
No Results Found
#endforelse
<div class="pt-2 pagination-sm">
{{ $results->links('vendor.pagination.bootstrap-4') }}
</div>
This code worked well where i was able to search and display results properly along with search time.
Now i want to do the same with laravel api and vuejs frontend. So this is what i tried
public function index(Request $request)
{
$start_search = microtime('s');
$searchterm = $request->input('search');
if($request->has('search')){
$results = Web::search($searchterm)->paginate(10);
} else {
$results = Web::latest()->paginate(10);
}
$stop_search = microtime('s');
$time_search = ($stop_search - $start_search);
return WebResource::collection($results);
}
I created a collection resource for the same.
Question 1. My question related to controller code, how to return $searchterm and $time_search so that i can use them on the frontend.
In my vue component, i tried with my learning till now
<template>
other code..
<div class="mb-3" v-for="result in results" :key="result.results">
<router-link :to="result.url" class="text-primary clear h-1x"> {{ result.meta_title }} </router-link>
<span class="h-2x">{{ result.meta_description }}</span>
</div>
</template>
<script>
import axios from 'axios'
import { mapGetters } from 'vuex'
export default {
layout: 'main',
computed: mapGetters({
locale: 'lang/locale',
authenticated: 'auth/check'
}),
metaInfo () {
return { title: this.$t('searchpagetitle') }
},
data: function () {
return {
results: [],
title: window.config.appName
}
},
watch: {
locale: function (newLocale, oldLocale) {
this.getResults()
}
},
mounted() {
console.log(this.locale)
this.getResults ()
},
methods: {
getResults() {
var app = this;
axios.get('/api/web')
.then(response => {
// JSON responses are automatically parsed.
this.results = response.data.data
})
.catch(e => {
this.errors.push(e)
})
}
}
}
</script>
Question 2: My second question related to vuejs, how to create a search form and render results according to the search and with proper search url ending with ?searchterm=searchkeywords in my case.
When i used blade i used the normal html form with action url so that it rendered results. Also i used $searchterm to use the same search terms to search in other routes like images, videos.
I just used {{ url('/images?searchterm='.$searchterm) }} in the href so that when user clicks on it, it renders results of all images with the same keyword just like google. And also used placeholder as "enter your search" and value as "{{$searchterm}}" so that the search term stayed in the search form too.
I want to know how to do all the same in vuejs.
Thank you
It is better to append the search keyword in request URL of API in frontend. So your request url will be like
axios.get('/api/web?searchterm='+this.searchterm)
And in your Laravel controller, you can get this value by using Input::get() , so your code to get searchterm will be
$searchterm = Input::get('searchterm');
And then you can fetch your data on basis of $searchterm variable.
I'm using redux-form. I have an onSubmit and a checkStatus method which both make an Ajax call to the API back-end. If the result of the Ajax call is not 200, I want to throw a SubmissionError.
The SubmissionError works fine if I throw it inside of onSubmit (it correctly shows me an error message on the form). But if I throw it inside of checkStatus, then I get an error complaining about an handled exception:
Uncaught (in promise) SubmissionError {errors: {…}, message: "Submit
Validation Failed", name: "SubmissionError", stack: "SubmissionError:
Submit Validation Failed at ...) at <anonymous>"}
I did see this comment that makes is seem like you are only supposed to throw SubmissionError from within onSubmit():
Here is my code:
import * as React from "react";
import { reduxForm, touch, Form, SubmissionError } from 'redux-form';
import ReduxFormField from './components/ReduxFormField'
export interface FormProps {
handleSubmit: any;
error: any;
}
export class MyForm extends React.Component<FormProps, any> {
private _inputVal: any;
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
this.checkStatus = this.checkStatus.bind(this);
}
checkStatus() {
return fetch("/checkStatus", {
method: 'GET',
}).then(response => {
if (response.status === 200) {
// checkStatus was successful!
} else {
throw new SubmissionError({
_error: "There was an error."
});
}
});
}
onSubmit(event) {
return fetch("/submit", {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({'key1': 'val1'})
}).then(response => {
if (response.status === 200) {
// submit was successful!
} else {
throw new SubmissionError({
_error: "There was an error."
});
}
});
}
render() {
return (
<form onSubmit={this.props.handleSubmit(this.onSubmit)}>
<div>
<fieldset>
<ReduxFormField
type="text" fieldName="myInputValue"
ref={(input) => {
this._inputVal = input;
}}/>
</fieldset>
<input type="submit" value="Submit"/>
<a onClick={() => {
this.checkStatus()
}
}>Check Status
</a>
</div>
</form>
)
}
}
export default reduxForm({
form: 'myForm'
})(MyForm);
I suppose this action creator should help
https://redux-form.com/7.2.0/docs/api/actioncreators.md/#-code-setsubmitfailed-form-string-fields-string-code-
setSubmitFailed(form:String, ...fields:String) #
Flips submitFailed flag true, removes submitSucceeded and submitting, marks all the fields passed in as touched, and if at least one field was passed flips anyTouched to true.
Another option if to create a formField ( I don't mean a visible field, but just inside redux-form) called 'checkStatus' being true by default. When your check fails, simply dispatch action called change onto this field and supply the reduxForm with a validator which fails if field if false