Passing laravel variables to Vue frontend - javascript

in order to pass php variables from laravel to vue frontend I created a Javascript class, I use this class static put method to send an associative array to frontend.
<?php
namespace App\Helpers;
class Javascript
{
public static function put($array, $request)
{
//I call this static method to pass backend variables to Vue, from blade I json_encode the payload, assign it to a window variable
//and later add it to the Vue.prototype so I can access in vue components like this.$app.whatever.
//This helper method can be called more than one time in laravel's request->reponse cycle, from middleware, controller action, route redirect ...
//so instead of creating recreating $app array everytime I want to find a way to push passed key value pairs to a global javascript object
$app = array();
$app = array_merge($request->globals, $array);
view()->share('app', $app);
}
}
When I want to return a laravel blade view wth javascript data I do it like this:
$featuredPosts = Post::where('isFeatured', true)->where('isVisible',true)->with('postcategory')->get();
Javascript::put([
'meta' => $meta,
'featuredPosts' => $featuredPosts,
], $request);
return view('publicaciones.list', compact('meta'));
And in my blade master layout:
<script type="text/javascript">window.$app = {!! json_encode( $app ) !!};</script>
Another case is when I want to have global variables for all routes/views, for this purpose I have a global middleware called GlobalsVar where I do.
public function handle($request, Closure $next)
{
$globals['auth'] = Auth::user() ? User::with('appointment')->find(Auth::id()) : false;
$globals['previousUrl'] = URL::previous();
$request->globals = $globals;
return $next($request);
}
Currently inside my Javascript class I create an empy array and merge part of my requests with the passed array from my controllers, I also pass request object as seconda parameter, I want to improve this in two ways:
1) Each time I call Javascript::put static method the passed values are merged into the exisiting object, this is because if during the request -> response cycle I call Javascript::put the payload is recreated and previous data is lost, is there a way to preserve this data?
2) I don't want to pass Request $request object each time I run Javascript::put, is there a way to always inject the Request method

if your call vue from blade you can pass laravel data like props
#extends('index')
#section('contenido')
<div id="content-container">
<div id="page-head">
</div>
<div id="page-content">
<vue-file :variable="{{ $variable}}"></vue-file>
</div>
#endsection
and in the vue-file you can get it like this
props:{
variable:Array
}

Related

How do i get access to this array, vuejs

How do I get access to this array, inside it has objects, I used laravel, inertiajs, vuejs, Im passing the variable from laravel controller to vuejs component with inertia.js
public function index($slug,Category $categories)
{
$category = $categories->where('slug',$slug)->with('product')->get();
return Inertia::render('Category',[
'categories' => $category
]);
}
If I understand your point correctly , I think you would like to access the products , then it's better to return from the controller to vue only the products.
and according to the variable naming I think you are expecting only one category to be returned then may be you need to check retrieving single model using ->first()
https://laravel.com/docs/8.x/eloquent#retrieving-single-models
You can loop with v-for or access directly:
categories[0].description

AJAX request to Laravel resource controller, best practice

I have set up a resource controller in Laravel with the following index function:
public function index()
{
if (!Auth::check()) {
return redirect()->route('login');
}
$decks = Auth::user()->decks->sortByDesc('name');
return view('decks.index')->with('decks', $decks);
}
On a different page I also need the $decks variable via a AJAX call. Right now I have set up an additional route to my controller, from which I can retrieve the decks via a GET request:
public function getDecks()
{
if (!Auth::check()) {
return;
}
$decks = Auth::user()->decks->sortByDesc('name');
return response()->json($decks);
}
My question: Is there a way to get the $decks variable via a request directly to index or is my solution the way to go?
If I make a get request to index I get the HTML of the decks.index view, but how can I access (if possible) the $decks variable?
I guess what I don't really grasp is this: What happens to $decks in the ->with('decks', $decks) statement? I know I can then access $decks using blade syntax on that page, but from where does it access the data and can I also access it via AJAX?
Yes! You can return different results depending on what kind of request was done. There is no need for 2 routes:
public function index(Request $request)
{
$decks = Auth::user()->decks->sortByDesc('name');
if ($request->ajax()) {
return response()->json(['decks' => $decks]);
} else {
return view('decks.index')->with('decks', $decks);
}
}
#Sven Hakvoort is right, you should check for authentication in the route definition:
Route::group(['middleware' => 'auth'], function () {
Route::get('/decks', 'DecksController#index');
// ... some other routes which requires authentication
}
You can not retrieve the $decks from the index route directly. When you call view(..)->with(...) it is internally passed to the blade template processor which also receives the $decks variable, the HTML is then build on the server-side and the 'compiled' HTMl is then returned to the browser. So once the server returns the result the $decks variable is not present anymore. Because of this behavior it is not possible to do what you want.
So yes, your solution is the way to go, although you might consider wrapping the Auth::check() in a middleware and move the call to $decks to a separate function in order to simplify your code.
I hope this answers your question, if anything is unclear feel free to ask!
Your solution is the proper way. It is not typically a good idea to handle any business logic or data retrieval using your routes - using a controller is preferred, which is what you are doing. If you want to avoid the if (Auth::check()) statement in your controller, you could add the auth middleware directly to that route like this.
Route::get('example', 'YourController#index')->middleware('auth');
Regarding your question about ->with('decks', $decks):
That function is sending your $decks variable to the view to be rendered in the blade template. That data is used by the server to render the page, and then the variable is discarded. If you want to also be able to work with that data on your page using javascript, you could do something like this in your blade template.
<script>
var decks = {!!$decks->toJSON()!!};
</script>

How exactly works this AngularJS factory example? Some doubts

I am absolutly new in AngularJS and I am studying it on a tutorial. I have a doubt related the use of the factory in Angular.
I know that a factory is a pattern used to create objects on request.
So in the example there is the following code:
// Creates values or objects on demand
angular.module("myApp") // Get the "myApp" module created into the root.js file (into this module is injected the "serviceModule" service
.value("testValue", "AngularJS Udemy")
// Define a factory named "courseFactory" in which is injected the testValue
.factory("courseFactory", function(testValue) {
// The factory create a "courseFactory" JSON object;
var courseFactory = {
'courseName': testValue, // Injected value
'author': 'Tuna Tore',
getCourse: function(){ // A function is a valid field of a JSON object
alert('Course: ' + this.courseName); // Also the call of another function
}
};
return courseFactory; // Return the created JSON object
})
// Controller named "factoryController" in which is injected the $scope service and the "courseFactory" factory:
.controller("factoryController", function($scope, courseFactory) {
alert(courseFactory.courseName); // When the view is shown first show a popupr retrieving the courseName form the factory
$scope.courseName = courseFactory.courseName;
console.log(courseFactory.courseName);
courseFactory.getCourse(); // Cause the second alert message
});
And this is the code, associated to this factoryController controller, inside the HTML page:
<div ng-controller="factoryController">
{{ courseName }}
</div>
So it is pretty clear for me that:
The factoryController use the courseFactory factory because is is injected
The first thing that happen when I open the page is that an alert mesage is shown because it is called the:
alert(courseFactory.courseName);
Then put into the $scope.courseName property (inside the $scope object) the value of the **courseName field of the courseFactory JSON object).
And here my first doubt. I have that the factory is defined by:
.factory("courseFactory", function(testValue)
that I think it means (correct me if I am doing wrong assertion) that my factory is named courseFactory and basically is a function that retutn the courseFactory JSON object.
So this is creating me some confusion (I came from Java) because in Java I call a factory class and I obtain an instance of an object created by the factory. But in this case it seems to me that doing:
$scope.courseName = courseFactory.courseName;
it seems to me that the courseName is retrieved directly by the courseFactory JSON object and I am not using the courseFactory.
How it exactly works? Why I am not calling some getter on the factory? (or something like this)
To simplify things There are two known methods to create functions ( and methods ) that are Usable among all states ( consider it as creating a function in global scope ) , these are factory and service.
you may want to read this first Factory vs Service
it seems to me that the courseName is retrieved directly by the
courseFactory JSON object and I am not using the courseFactory.
Actually this is partially true , as Angular use DI concept ( depency injection ) , you will have to inject your factory ( which by default returns an object , and corresponding functions as attributes ) , case you don't ; you will not be able to use your factory object methods.
Angular is not magic , it is just most people don't realize the most basic concepts of JavaScript , specially Developers coming from different programming environment such as C# , C++ , or Java
Easy.
When you return the courseFactory object in the factory statement, the injected courseFactory in the controller becomes THAT object. Therefore, when you do $scope.courseName = courseFactory.courseName; in the controller, you are actually referencing to the returned object that is injected into the controller as courseFactory. So you don't need a getter, because the courseFactory in your controller is already the object. You can do a console.log(courseFactory); in your controller to see what the courseFactory is. Hope this helps.
When an Angular application starts with a given application module,
Angular creates a new instance of injector, which in turn creates a
registry of recipes as a union of all recipes defined in the core "ng"
module, application module and its dependencies. The injector then
consults the recipe registry when it needs to create an object for
your application.
Ref. https://docs.angularjs.org/guide/providers
Factory is a Singleton service. When you inject the factory in the controller or in any other factory, u get the exact json object which u have defined. It will not create any new instance every time you call it. Factory is initialized only once

looking up in store from a component

I have a template that includes a component.
// pods/workgroup/template.hbs
...
{{workgroup/member-add
wgId=model.id
store=store
peekUser2Workgroup=peekUser2Workgroup
}}
...
Within that component I need to lookup if something is already present in the store.
//somewhere in components/workgroup/member-add/componsent.js
let alreadyInStore = this.store.peekRecord('user2workgroup',u2wId);
I made it work by injecting the store into the component (as above), which of course is bad practise.
So I tried making a property in my parent-controller that does the store lookup:
//in components/workgroup/member-add/componsent.js
let alreadyInStore = this.get('controller').peekUser2Workgroup(u2wId);
//in pods/workgroup/controller.js
peekUser2Workgroup: function(u2wId) {
console.log(this);
console.log(this.store);
return this.store.peekRecord('user2workgroup',u2wId);
}
This works fine as long as I pass the complete store into the compentent as above.
However, if I don't pass the store to the component it get's undefined, although never accessed from the component directly (the store is present in the controller alone).
Logging into console of this gives me surprisingly the component, not the controller, this.store is undefined.
So I've learned, that with this I don't access the controller itself when a function/parameter gets called from outside/a component.
The question is, how can I make the controller to reference to itself with this?
Or how can I access the store when calling a parameter from outside?
Do I really need to pass the controller itself to himself??
like so:
// in component
let alreadyInStore = this.get('controller').peekUser2Workgroup(this.get('controller'), u2wgId);
//in controller
peekUser2Workgroup: function(myself, u2wId) {
console.log(this);
console.log(this.store);
return myself.store.peekRecord('user2workgroup',u2wId);
}
That seems very odd to me, and looks like I'm shifting around even more than I did initially when simply injecting the store to the controller...
Ember: 2.0.1
Ember-Data: 2.0.0
Instead of passing the store into the component as a property, inject it using Ember.service like this:
store: Ember.service.inject()
Then instead of passing in the function, just pass in the id vale you're looking up:
{{workgroup/member-add
wgId=model.id
}}
Now in your component you can fetch the record:
workgroup: function(){
return this.get('store').peekRecord('user2workgroup', this.get('wgId'));
}.property()

How to pass an array from a server with SignalR and present the result using Knockout

I am playing with SignalR and KnockoutJS and can't seem to find a simple way to get an array from the database presented using the MVC4 framework.
I have no problem sending a single object from the server - but when I try to send an array I get stuck. Hopefully someone with more experience can spot the probably obvious mistakes I am making, and show how this should be done (JavaScript is not my strong side). The problem as far as I can understand is the mapping of the data passed from the server. Any help is much appreciated!
The SignalR Hub (orders is a simple table with Id and Name)
public class feedHub : Hub
{
private dataContext db = new dataContext();
public void GetAll()
{
var orders = db.orders.ToArray();
Clients.getData(orders);
}
}
Simple HTML code to present the orders;
<div id="Demo">
<div data-bind="foreach: orders">
<div data-bind="html: Id"></div>
<div data-bind="html: Name"></div>
</div>
</div>
JavaScript
<script type="text/javascript">
var viewModel = {
orders: ko.observableArray(orders)
};
ko.applyBindings(viewModel, $("#Demo")[0]);
$(function () {
// Client side version of the feebHub class
var hubcon = $.connection.feedHub;
// getData called from server
hubcon.getData = function (data) { viewModel.orders(data) };
// Start connection and call getAll
$.connection.hub.start(function () { hubcon.getAll(); });
});
</script>
A couple of points:
Just use ko.observableArray(), i.e. without the parameter
Put the call to ko.applyBindings inside your ready function, e.g. just before you get your hub reference
That should be enough to get it working. At least, it works me in this fiddle which I based on your code.
One further point though ... you are passing plain JSON objects to KO (i.e. inside your observable array). This is like data-binding in C# against some classes that do not implement INotifyPropertyChanged. IOW the binding will work properly once and changes in the objects will never get reflected on the UI. If you want SignalR to feed changes into your objects, then they will need to have observable properties and you might want to look into the KO mapping plugin.

Categories

Resources