axios.get("/api/session/" + this.roomId)
Above is a snippet from my axios call that uses my api.php route ('/api/session/{id} that loads through the controller the requested specific room => /api/session/3 is room 3).
Currently, this snippet is harcoded and always uses integer 1 for 'this.roomId'.
I did that, in oder to check if my vue is even working fine.
My question is now, how am I able to use a dynamic param for my prop roomId?
so I can always say something like
.get/.post('url', $id) ?
If you're passing the roomId as a prop into the component then you need to handle the change in the parent component. For that I'd need a bit more context on where the room-ids come from and how you select the room-id there.
If you have this part down, then you'll want to watch changes on the roomId prop and re-fetch the data when ever it changes. You can do something like this in your room component:
<script>
import axios from 'axios'
const props: {
roomId: {
type: Number,
required: true
}
}
export default {
props,
data() {
return {
room: null
}
},
methods: {
async fetchRoom() {
try {
const response = await axios.get(`/api/session/${this.roomId}`)
this.room = response.data
} catch (err) {
// - handle error
}
}
},
watch: {
roomId: {
immediate: true // so it's executed when component is created
handler: function () {
this.fetchRoom()
}
}
}
}
</script>
Related
I've been trying to load all of my data when the time I log in. Currently, I've only managed to display data through the console through vuex file. I just want to achieve this because wherever it loads all data when login, it will easier for me to call every function on every page.
I think the first step is to display it on vue devtools?
This is what I've tried.
I have this file on my "./store/modules/currentUser.js"
import axios from "axios";
const state = {
};
const getters = {};
const actions = {
loadEmployee({}){
axios.post(BASE_URL + '/transportation/driver/autoComplete').then(response => {
console.log(response.data); // how to pass result to devtools?
});
}
};
const mutations = {};
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Login.vue
<script>
export default {
data () {
return {
listdata:[]
}
},
methods: {
login() {
this.$store.dispatch('currentUser/loadEmployee', this.listdata);
}
}
}
</script>
This is my vuedevtools looks like
And I want to fetch all data on listdata array vue devtools
If you are using vuex, you should probably load state in dev tools.
However, your issue is caused by not having a mutation, so you never update the state.
import axios from "axios";
const state = {
transansportDrivers: []
};
const getters = {};
const actions = {
loadEmployee({}){
axios.post(BASE_URL + '/transportation/driver/autoComplete').then(response => {
commit('setTransportDrivers', response.data)
});
}
};
const mutations = {
setTransportDrivers: (state, drivers) => {
state.transansportDrivers= drivers;
},
};
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
I have a user.service, a list.page.ts and a list.page.html.
And I want to display data from the backend (php). I am getting Data in the console log, but it doesn't display on the website. Please Help.
Thank you!
user.servive
export enum SearchType {
all = '',
name = 'name',
stadt = 'stadt'
}
#Injectable({
providedIn: 'root'
})
export class UserService {
url = 'http://127.0.0.1:8000/getallrestaurants';
constructor(public http: HttpClient) { }
searchData(name: string, type: SearchType): Observable<any> {
return this.http.get('http://127.0.0.1:8000/getallrestaurants')
.pipe(
map(results => {
console.log('RAW: ', results);
return results['Search'];
})
);
}
list.page.ts
export class ListPage implements OnInit {
results: Observable<any>;
searchTerm = '';
type: SearchType = SearchType.all;
constructor(private userService: UserService) { }
ngOnInit() {}
searchChanged() {
this.results = this.userService.searchData(this.searchTerm, this.type);
}
list.page.html
<ion-searchbar [(ngModel)]="searchTerm" (ionChange)="searchChanged($event)"></ion-searchbar>
<ion-item>
<ion-label>Select Searchtype</ion-label>
<ion-select [(ngModel)]="type" (ionChange)="searchChanged($event)">
<ion-select-option value="">All</ion-select-option>
<ion-select-option value="stadt">Stadt</ion-select-option>
<ion-select-option value="name">Name</ion-select-option>
</ion-select>
</ion-item>
<ion-list>
<ion-item button *ngFor="let item of (results | async)" [routerLink]="['/', 'list', item.imdbID ]">
<ion-icon [name]="item.icon" slot="start"></ion-icon>
<p>Hallo User: {{item.name}}</p>
</ion-item>
This is my console.log, as you see i get the data, now i want it to show for example the name on frontend.
Ok I see the problem here in the class user.service you have to change it like this.
searchData(name: string, type: SearchType): Observable<any> {
return this.http.get('http://127.0.0.1:8000/getallrestaurants')
.pipe(
map(results => {
console.log('RAW: ', results);
return results;
})
);
}
You have to remove the ['Search'] because your JSON Response has no entry which is like 'Search'.
If you're seeing console.log update then this is most likely an issue with the html template not knowing some data changed that it needs to re-render and update the view for. Angular has built in change detection strategy but as the developer you can also manually interact with it. Checkout (https://angular.io/api/core/ChangeDetectorRef) for further explanation on this topic.
As for your code, try inserting the change detection reference as so by importing ChangeDetectorRef from #angular/core, and then check for changes of data to tell the view to re-render.
list.page.ts
export class ListPage implements OnInit {
results: Observable<any>;
searchTerm = '';
type: SearchType = SearchType.all;
constructor(private userService: UserService, private ref: ChangeDetectorRef) { }
ngOnInit() {}
searchChanged() {
this.results = this.userService.searchData(this.searchTerm, this.type);
this.ref.detectChanges()
}
Note: this will execute every time the user types and it may slow down your application because you're forcing angular to check for changes every time you call searchChanged(). I would thereby implement some sort of debounce technique to stall redundant or unnecessary calls to searchChanged(). Check out this resources to learn more about debouncing if this issue comes up (https://rxjs-dev.firebaseapp.com/api/operators/debounce).
So I am using Laravel 5.5. I have a data coming from my Controller and I want to pass it to my root vue instance not the component.
So for example I have the Dashboard Controller which has a data of "users"
class DashboardController extends Controller {
public function index(){
$user = User::find(1);
return view('index', compact('user'));
}
}
I am using Larave mix on my project setup. So my main js file is the app.js. That "$user" data I need to pass on the root Vue instance. Which is located in app.js
const app = new Vue({
el: '#dashboard',
data: {
// I want all the data from my controller in here.
},
});
If you don't want to use an API call to get data (using axios or else), you could simply try this :
JavaScript::put(['user' => $user ]);
This will, by default, bind your JavaScript variables to a "footer" view. You should load your app.js after this footer view (or modify param bind_js_vars_to_this_view).
In app.js :
data: {
user: user
}
Read more : https://github.com/laracasts/PHP-Vars-To-Js-Transformer
I would make a request to fetch the user's data as has been suggested.
Alternatively, you can add a prop to the dashboard component in index.blade.php and set the user like <dashboard :user="{{ $user }}"></dashboard>. You'll probably want to json_encode or ->toArray() the $user variable.
Then within the dashboard component you can set data values based on the prop.
props: ['user'],
data () {
return {
user: this.user
}
}
I just solved this by placing a reference on the window Object in the <head> of my layout file, and then picking that reference up with a mixin that can be injected into any component.
TLDR SOLUTION
.env
GEODATA_URL="https://geo.some-domain.com"
config/geodata.php
<?php
return [
'url' => env('GEODATA_URL')
];
resources/views/layouts/root.blade.php
<head>
<script>
window.geodataUrl = "{{ config('geodata.url') }}";
</script>
</head>
resources/js/components/mixins/geodataUrl.js
const geodataUrl = {
data() {
return {
geodataUrl: window.geodataUrl,
};
},
};
export default geodataUrl;
usage
<template>
<div>
<a :href="geodataUrl">YOLO</a>
</div>
</template>
<script>
import geodataUrl from '../mixins/geodataUrl';
export default {
name: 'v-foo',
mixins: [geodataUrl],
data() {
return {};
},
computed: {},
methods: {},
};
</script>
END TLDR SOLUTION
If you want, you can use a global mixin instead by adding this to your app.js entrypoint:
Vue.mixin({
data() {
return {
geodataUrl: window.geodataUrl,
};
},
});
I would not recommend using this pattern, however, for any sensitive data because it is sitting on the window Object.
I like this solution because it doesn't use any extra libraries, and the chain of code is very clear. It passes the grep test, in that you can search your code for "window.geodataUrl" and see everything you need to understand how and why the code is working.
That consideration is important if the code may live for a long time and another developer may come across it.
However, JavaScript::put([]) is in my opinion, a decent utility that can be worth having, but in the past I have disliked how it can be extremely difficult to debug if a problem happens, because you cannot see where in the codebase the data comes from.
Imagine you have some Vue code that is consuming window.chartData that came from JavaScript::put([ 'chartData' => $user->chartStuff ]). Depending on the number of references to chartData in your code base, it could take you a very long time to discover which PHP file was responsible for making window.chartData work, especially if you didn't write that code and the next person has no idea JavaScript::put() is being used.
In that case, I recommend putting a comment in the code like:
/* data comes from poop.php via JavaScript::put */
Then the person can search the code for "JavaScript::put" and quickly find it. Keep in mind "the person" could be yourself in 6 months after you forget the implementation details.
It is always a good idea to use Vue component prop declarations like this:
props: {
chartData: {
type: Array,
required: true,
},
},
My point is, if you use JavaScript::put(), then Vue cannot detect as easily if the component fails to receive the data. Vue must assume the data is there on the window Object at the moment in time it refers to it. Your best bet may be to instead create a GET endpoint and make a fetch call in your created/mounted lifecycle method.
I think it is important to have an explicit contract between Laravel and Vue when it comes to getting/setting data.
In the interest of helping you as much as possible by giving you options, here is an example of making a fetch call using ES6 syntax sugar:
routes/web.php
Route::get('/charts/{user}/coolchart', 'UserController#getChart')->name('user.chart');
app/Http/Controllers/UserController.php
public function getChart(Request $request, User $user)
{
// do stuff
$data = $user->chart;
return response()->json([
'chartData' => $data,
]);
}
Anywhere in Vue, especially a created lifecycle method:
created() {
this.handleGetChart();
},
methods: {
async handleGetChart() {
try {
this.state = LOADING;
const { data } = await axios.get(`/charts/${this.user.id}/coolchart`);
if (typeof data !== 'object') {
throw new Error(`Unexpected server response. Expected object, got: ${data}`);
}
this.chartData = data.chartData;
this.state = DATA_LOADED;
} catch (err) {
this.state = DATA_FAILED;
throw new Error(`Problem getting chart data: ${err}`);
}
},
},
That example assumes your Vue component is a Mealy finite state machine, whereby the component can only be in one state at any given time, but it can freely switch between states.
I'd recommend using such states as computed props:
computed: {
isLoading() { return (this.state === LOADING); },
isDataLoaded() { return (this.state === DATA_LOADED); },
isDataFailed() { return (this.state === DATA_FAILED); },
},
With markup such as:
<div v-show="isLoading">Loading...</div>
<v-baller-chart v-if="isDataLoaded" :data="chartData"></v-baller-chart>
<button v-show="isDataFailed" type="button" #click="handleGetChart">TRY AGAIN</button>
I am using laravel 5.
I have a custom action in my controller. By custom I mean it is not used by the resource object in angular. The following is the code of my controller.
class ServicesController extends Controller {
public function __construct()
{
$this->middleware('guest');
}
public function extras()
{
// code here
}
}
This is my service code in the angular script.
(function() {
'use strict';
angular
.module('bam')
.factory('myservice', myservice);
function myservice($resource) {
// ngResource call to the API for the users
var Serviceb = $resource('services', {}, {
update: {
method: 'PUT'
},
extras: {
method: 'GET',
action: 'extras'
}
});
function getExtras(){
return Serviceb.query().$promise.then(function(results) {
return results;
}, function(error) {
console.log(error);
});
}
}
})();
Now, the query() here will send the request to the index method in the laravel controller. How will I access the extras() action in the getExtras() method?
It looks like you're almost there try out the example below I tried to use what you have in your question, and added a few other custom endpoints as examples. You'll want a base URL set up similarly to the example so you can feed it an id out of your payload so $resource can set up your base CRUD. Otherwise to make custom routes using the same resource endpoint you can add some extra actions like you have in your question, but apply your customization on the base endpoints URL.
.factory('ServicesResource', ['$resource',
function ($resource) {
// Parameters used in URL if found in payload
var paramDefaults = {
id: '#id',
param: '#param'
}
// Additional RESTful endpoints above base CRUD already in $resource
var actions = {
custom1: {
method: 'GET',
url: '/api/services/custom',
},
custom2: {
method: 'GET',
url: '/api/services/custom/:param',
},
extras: {
method: 'GET',
url: '/api/services/extras'
}
update: {
method: 'PUT'
}
}
// Default URL for base CRUD endpoints like get, save, etc
return $resource('/api/services/:id', paramDefaults, actions);
}])
Now you can dependency inject the factory and use it like this:
var payload = {param:'someParam'};
ServicesResource.custom(payload).$promise.then(function(response){
// handle success
}, function(reason) {
// handle error
});
Or for Extras:
ServicesResource.extras().$promise.then(function(response){
// Handle success
}, function(reason) {
// Handle error
});
In Laravel you're route might be something like this:
Route::get('services/{param}/custom', 'ServicesController#custom');
Or for extras like this:
Route::get('services/extras', 'ServicesController#extras');
I got what I wanted using $http.
function getExtras(){
return $http.get('/services/extras').success(function (results) {
return results;
});
}
But, that would be nice if anyone suggest me how to do it with Serviceb.query().$promise.then.
I have an Ext Grid and want to grab the JSON "success":false/true response an execute a function for each situation. I would like to have it as callback function for every grid interaction with the JSON PHP file.
Any examples of this ?
Thank you for your time.
You need to register callbacks to the load and exception events of the JsonStore. Something like this:
var grid = new Ext.grid.GridPanel({
store: new Ext.data.JsonStore({
[...]
listeners: {
load: this.onLoadSuccess.crateDelegate(this),
exception: this.onLoadException.createDelegate(this)
}
}),
onLoadSuccess: function () {
// success
},
onLoadException: function () {
// error
},
[...]
}