How do I set initial vuex state in Laravel? - laravel

I have the data I am looking for in a controller and need to set some state in vuex. Do I need to make a second database request, or is there some way for me to pass the value from my controller to vuex?
I am trying to pass the value down as props and change a null state, but when I change the state, the value is still being passed down.
Is there a way to pass the value from the controller to vuex, or do I have to double my requests and make 2 calls just to load the same data?

You can do a second query to fetch the initial state OR get these values through window.App (or whatever).
window.App = {
initialState: {{ !empty($myInitialState) ? json_encode($myInitialState) : '' }}
};
In Vue.js, update the initial vuex state using window.App.initialState;
created () {
this.$store && this.$store.dispatch('SET_INITIAL_STATE', window.App.initialState || {})
}

Related

Passing data from blade to blade in Laravel

I have a page where you can create your workout plan. Second page contains "pre-saved" workouts and I want them to load by passing parameters from second page to first. If you directly access first page, you create your workout plan from scratch.
// first page = https://prnt.sc/y4q77z
// second page = https://prnt.sc/y4qfem ; where you can check which one you want to pass to first page
// final step looks like this: https://prnt.sc/y4qh2q - but my URL looks like this:
www.example.com/training/plan?sabloni%5B%5D=84&sabloni%5B%5D=85&sabloni%5B%5D=86
this 84,85,86 are IDS
Can I pass params without changing URL ? Like having only /training/plan without anything after ?
public function plan(Request $request){
$workout = false;
if($request->workout){
$workout = $request->workout;
$workout = SablonTrening::find($sabloni); // $workout = array [1,3,4,5,6]
}
return view('trener.dodaj_trening', compact('workout'));
}
If you are getting to the /training/plan page with GET request, you could simply change it to POST. That way the parameters would be hidden in the URL but would be present in the request body. You would need a new post route:
Route::post('/training/plan', 'YourController#plan')->name('training.plan');
And then, in the form where you are selecting these plans, change the method on submit:
<form action="{{route('training.plan')}}">
//Your inputs
</form>
Your method should still work if your inputs stay the same.
Note: Not sure you would still keep the functionalities that you need, since I can't see all the logic you have.
If you have any questions, let me know.
To pass data from on blade to another blade.
At the end of first post before redirect()-route('myroute') add $request->session()->put('data', $mydata);
At the begining of the route 'myroute', just get back your data with $data = $request->old('data');

Laravel 5.8 + Vue2JS Session and Old values in component

I have question about normal laravel multi form with post action as method based on laravel session. I added in this form component of vue, which is simple city autocomplete. I want load to inputs into fields of this component from session (session()), or old (old()) values, if session exist i want to load from session city and province, but if session doesnt exist, but old laravel values exist I want to load them in this component form, if they doesnt exist, leave fields empty. What's the easiest way to do that?
Get the session and pass a default which would be the old value.
$data = session('session_data_key', $old_value); // however you get the old value is up to you.
Pass it down to your view. If no session is set on the server, it will use the default (if default is null it will not set the auto-complete).
UPDATE
If you are using axios to make calls to a laravel app, before loading the form component (in mounted() {}) do a call to axios to get the value of (session or old value). This is what you'll load into the form.
axios.get('/api/load_dafault').then(resp => {
this.defaultValueToBePassedToField = resp.data.value;
});
The endpoint '/api/load_dafault' or whatever yours is named, will have it's controller like so:
public function loadDefaults()
{
$old_value = ... // however you get it is up to you.
$data = session('session_data_key', $old_value);
}
Do not forget to ensure you set the routes.

KeystoneJS: How to set a field to receive randomly generated value?

I'm creating a model that I will use to authenticate users for API access, and I have a secret field where I want to store a Base64 encoded uuid/v4 generated value.
I went through the different field types and options, but still not seeing how I could achieve this.
Is there a way to hook in model instance creation, and set the value of my secret field ?
Yes, you can use the pre hooks.
In your situation, the basics would be:
AuthenticationModel.schema.pre("save", function(next) {
const secretValue = generateSecretValue();
this.secret = secretValue;
next();
});
That would go before your final AuthenticationModel.register(); in your model.js file.
This is how I set it up, also with the pre-save hook. My problem before was that I was getting the same random number again until I restarted the server.
Store.schema.pre('save', function (next) {
if (!this.updateId && this.isNew) {
// generates a random ID when the item is created
this.updateId = Math.random().toString(36).slice(-8);
}
next();
});
Using this.isNew was also useful in my case.

In a user's Edit Info form, how do I include the name of the field(s) and user's input value(s) in a response from the model

On a Yii2 project, in a user's Edit Info form (inside a modal):
I'm currently figuring out which fields were changed using the jQuery .change() method, and I'm grabbing their value with jQuery's .val() method.
However, I want to do less with JavaScript and do more with Yii's framework.
I can see in the Yii debugger (after clicking into the AJAX POST request) that Yii is smart enough to know which fields were changed -- it's showing SQL queries that only UPDATE the fields that were changed.
What do I need to change in the controller of this action to have Yii include the name of the field changed -- including it's value -- in the AJAX response? (since my goal is to update the main view with the new values)
public function actionUpdateStudentInfo($id)
{
$model = \app\models\StudentSupportStudentInfo::findOne($id);
if ($model === null) {
throw new NotFoundHttpException('The requested page does not exist.');
}
$model->scenario = true ? "update-email" : "update-studentid";
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->renderAjax('_student_support_alert_success');
}
return $this->renderAjax("_edit_student_info",[
"model" => $model,
]);
}
I'm currently returning a static success view.
You can use $model->dirtyAttributes just after load the data to get a $attrib => $value pair array.
http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#getDirtyAttributes()-detail (this docs says:)
Returns the attribute values that have been modified since they are loaded or saved most recently.
The comparison of new and old values is made for identical values using ===.
public array getDirtyAttributes ( $names = null )
(sorry for formatting, sent by mobile)

Race condition between componentWillReceiveProps and componentDidMount

I have a component that takes some data in the props and make an ajax request with them.
var ItemList = React.createClass({
propTypes: {
filters: React.PropTypes.object.isRequired,
},
getInitialState: function() {
return {items: []};
},
componentDidMount: function() {
this.ajaxFetchItems(this.props.filters);
},
componentWillReceiveProps: function(nextProps) {
this.ajaxFetchItems(nextProps.filters);
},
ajaxFetchItems: function(filter) {
....
this.setState({items: data});
}
}
The problem is that the props are changed almost immediately, and sometimes the ajax call in componentDidMount is slightly slower than the one in componentWillReceiveProps, so the initial state is written after the first update.
How can I avoid that a slow componentDidMount will overwrite a fast componentWillReceiveProps?
There are better ways to handle the lifecycle of a react component that downloads its data?
You could put a timestamp in state for the latest update processed.
And somehow make sure that the timestamp of the original Ajax request is included in the Ajax results.
And add a shouldComponentUpdate() to check if the received results have a timestamp that is later than the timestamp in state. If not: return false, and your component will ignore the results.
By the way: componentDidMount and componentWillReceiveProps can by definition only be run in that order. I suspect that your first Ajax call takes long to return result, and your second call is fast. So you get the Ajax results back in the wrong order.
(Not due to slow react functions).
UPDATE:
Using shouldComponentUpdate is the react-way of dealing with this case: Its purpose is to allow for comparison of the new state with the old state, and based on that comparison, not rerender.
The issue is (most likely) generated by the order in which ajax responses come in:
Ajax call 1 (fired in componentDidMount in this example)
Ajax call 2 (fired in componentWillReceiveProps, trigger by parent of component)
Response from call 2 comes in
Response from call 1 comes in.
So a more generic question/ solution would be for "How to handle ajax responses coming back in the wrong order".
The timestamp (in shouldComponentUpdate) is one way to do it.
An alternative (described here) is to make the second request (in componentWillReceiveProps) abort the first ajax request.
Revisit:
After giving it some further thought (the calls in componentDidMount and componentWillReceiveProps did not feel right), a more general react-like way to approach your component would probably be as follows:
Your component's job is basically to:
receive filter via prop,
use filter to fetch list with ajax,
and render ajax reponse = list.
So it has 2 inputs:
filter (= prop)
list (= ajax response)
and only 1 output = list (which may be empty).
Workings:
The first time component receives filter as prop: it needs to send out ajax request, and render an empty list or some loading state.
all subsequent filters: component should send out a new ajax request (and kill possible outstanding old requests), and it should NOT re-render (!).
whenever it receives an ajax response, it should re-render the list (by updating state).
Setting this up with react would probably look something like this:
getInitialState() {
this.fetchAjax(this.props.filter); // initiate first ajax call here
return { list : [] }; // used to maybe display "loading.." message
}
componentWillReceiveProps(nextProps) {
this.fetchAjax(nextProps.filter); // send off ajax call to get new list with new filter
}
shouldComponentUpdate(nextProps, nextState) {
return (this.state.list != nextState.list); // only update component if there is a new list
// so when new props (filter) comes in there is NO rerender
}
render() {
createChildrenWith(this.state.list);
}
fetchAjax(filter) {
killOutStandingRequests(); // some procedure to kill old ajax requests
getListAsync…
request: filter // request new list with new filter
responseHandler: this.handleResponse // add responseHandler
}
responseHandler(data) {
this.setState({ list : data }); // put the new list in state, triggering render
}
The original timestamp in state would solve the question posted above, but I thought I'd share the revised react component as a bonus...

Resources