I’m having a problem.
i have list of project i want when i click in one project he take me to another page(components) this is the component ProjectDetail when i can find the detail of that project Inside of it, I have this block of code:
this is the route who take me to another components:
{path: '/detail/:id', name: detail , component: detail },
I want to get the project with the id in the url detail from DB w but nothing Happen this is ProjectDetail.vue:
export default {
data(){
return{
id: this.$route.params.id,
projets:[],
projet:{
id:'',
name:'',
durre:'',
description:'',
budget:'',
owner:'',
}
}
},
methods:{
afficherProjets(){
axios.get('api/getProjects/'+this.id)
.then(data => {
this.projets = data.data;
});
}
},
mounted() {
console.log('Component mounted.')
this.afficherProjets();
}
}
and this is my controller:
public function getProjects($id)
{
return Projet::findOrFail($id);
}
in your vue.
export default {
data(){
return{
id: this.$route.params.id,
projet:{}
}
},
methods:{
//GETID
afficherProjet(){
axios.get('api/getProject/'+this.id)
.then(data => {
this.projet = data.data;
});
}
},
mounted() {
console.log('Component mounted.')
this.afficherProjet();
}
File in routes api.php
//ALL
Route::get('getProjects', ['uses' =>'API\ProjetController#getProjects']);
//SPECIFIQ ID
Route::get('getProject/{id}', ['uses' =>'API\ProjetController#getProject']);
In your controller, app/Http/API/ProjetController
public function getProjects()
{
return Projet::latest()->paginate(15);
}
public function getProject($id)
{
return Projet::findOrFail($id);
}
Your model projet
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Projet extends Model
{
public $timestamps = false;
protected $table = 'projets';
protected $fillable = [
'name',
'durre',
'description',
'budget',
'owner'
];
}
Do you have your model?
Your error comes from the 'data.data' i thing it's empty, you should just call 'data'.
Personally i prefer Mounted.
I thing now it's working!
Related
I just have two components, and the app is connected to firebase (firestore). The data called in ngOnInit disappears when I navigate and only appears again if I insert a Post or a User (forms).Why? Can someone help me out?
The routes:
const routes: Routes = [
{ path: "", component: HomeComponent, pathMatch: "full" },
{
path: "admin",
component: AdminComponent
},
{
path: "**",
redirectTo: "/",
pathMatch: "full"
}
];
The Service
itemsCollection: AngularFirestoreCollection<Post>;
items: Observable<Post[]>;
itemDoc: AngularFirestoreDocument<Post>;
constructor(public afs: AngularFirestore) {
this.itemsCollection = this.afs.collection('posts', ref =>
ref.orderBy('date', 'desc')
);
this.items = this.itemsCollection.snapshotChanges().map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Post;
data.id = a.payload.doc.id;
return data;
});
});
}
getItems() {
return this.items;
}
Its Component and the subscription
private postService: PostsService,
) {}
ngOnInit() {
this.postService.getItems().subscribe(data => {
this.postInput = data;
});
}
Create posts property in your service.
Then subscribe to your observable in your service, set posts to what u get from firebase.
Also dont write your code inside constructor but wrap in in a function and use it in OnInit in apropriate component. And lastly create a Subject send with it the current posts and subscribe to them in onInit inside desired components
posts = Post[]
postsChanged = new Subject<Post[]>()
getItems(){
this.itemsCollection.snapshotChanges().map(changes => {
return changes.map(a => {
return {
id: a.payload.doc.id,
...a.payload.doc.data()
}
}).subscribe(posts => {
this.posts = posts
this.postsChanged.next([...this.posts])
})
}
Based on Kase44 hints i managed to find a solution: wrapped the capture of the ID in a function, called it in the service constructor and in the ngOnInit():
The Service
export class UsersService {
usersCollection: AngularFirestoreCollection<Users>;
userDoc: AngularFirestoreDocument<Users>;
users: Observable<Users[]>;
user: Observable<Users>;
constructor(public afs: AngularFirestore) {
this.usersCollection = this.afs.collection('employees', ref =>
ref.orderBy('name', 'asc')
);
this.getUserID();
}
getUserID(){
this.users = this.usersCollection.snapshotChanges().map(changes => {
return changes.map(a => {
const data = a.payload.doc.data() as Users;
data.id = a.payload.doc.id;
return data;
});
});
}
And the component:
ngOnInit() {
this.userService.getUsers().subscribe(data => {
this.emp = data;
});
this.userService.getUserID();
}
I am reading data from a firebase database and creating some objects based on the data received and pushing the data into a list. But the control goes back to the component before the objects are created or pushed into the list. I am confused to use any life cycle hooks in this approach.
Class Service(){
questions: QuestionsData<any>[]=[];
getQuestions(FormKey: string) {
var dbQuestions = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
})
dbQuestions.subscribe(snapshots=>{
snapshots.forEach(elementData => {
this.questions.push(new TextboxQuestion({
key: elementData.elementname,
label: elementData.displaytext,
value: elementData.elementvalue,
required: false,
order: elementData.sortorder
}))
}
}
}
Can anyone suggest how to consume this data in my component.
As JB Nizet mentioned in the comments, you should not subscribe to the observable and unwrap it in your template as you are currently doing. Angular provides the async pipe to handle that subscription for you. You simply want to map your data to TextBoxQuestion's. You can do that with the following code.
class MyComponent {
questions$: QuestionsData<any>[]=[];
getQuestions(FormKey: string) {
const dbQuestions$ = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
});
this.questions$ = dbQuestions$.map(snapshots =>
snapshots.map(data => new TextBoxQuestion({
key: data.elementname,
// and so on...
});
}
}
If you want to run that when your component initializes, use the OnInit lifecycle hook:
ngOnInit() {
this.getQuestions(/* form key */);
}
And then use the async pipe in your template like this:
<ul>
<li *ngFor="let question of questions$ | async">
{{ question.key }}
</li>
</ul>
Your service should be more or less like this:
import 'rxjs/add/operator/map'
Class Service() {
getQuestions(FormKey: string): Observable<QuestionsData<any>[]> {
return dbQuestions = this.af.list('/elements', {
query: {
limitToLast: 200,
orderByChild: 'formid',
equalTo: FormKey
}
}).map(snapshots=>{
conts questions: QuestionsData<any>[]=[];
snapshots.forEach(elementData => {
questions.push(new TextboxQuestion({
key: elementData.elementname,
label: elementData.displaytext,
value: elementData.elementvalue,
required: false,
order: elementData.sortorder
}))
})
return questions;
})
}
}
And in the component:
serviceInstance.getQuestions(FormKey).subscribe(questions => {
// your code here
})
Im trying to load the data from my API to custom component using Angular2 ng Smart table plugin.
AS per their documentation (https://github.com/akveo/ng2-smart-table/blob/master/src/app/pages/examples/server/basic-example-load.component.ts)
i have my component like:
import { LocalDataSource } from 'ng2-smart-table';
import { ProductService } from '../../../services/product.service';
export class CategoryItemsComponent implements OnInit {
...
source: LocalDataSource;
constructor(private productService: ProductService,
private flashMessage: FlashMessagesService,
private router: Router,
http: Http) {
this.source = new LocalDataSource();
this.productService.getProductsOncategory(this.categoryid).subscribe((data) => {
this.source.load(data);
});
}
ProductService .ts
getProductsOncategory(category_id) {
let catUrl = "http://localhost:5000/products/getProductsOncategory"
let headers = new Headers();
headers.append('Content-Type', 'application/json');
let catIdObj = JSON.stringify({ category_id: category_id })
return this.http.post(catUrl, catIdObj, { headers: headers })
.map((response: Response) => response.json())
.do(data => console.log(JSON.stringify(data)))
.catch(this.handleError);
}
The above API used in the service function works perfect in my postman.
Now i need to load the dame data from that API into my custom component.
I am getting this error:
ERROR TypeError: this.data.slice is not a function
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/local/local.data-source.js.LocalDataSource.getElements (http://localhost:4200/1.chunk.js:22280:30)
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/data-source.js.DataSource.emitOnChanged (http://localhost:4200/1.chunk.js:22185:14)
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/data-source.js.DataSource.load (http://localhost:4200/1.chunk.js:22105:14)
at LocalDataSource.webpackJsonp.../../../../ng2-smart-table/lib/data-source/local/local.data-source.js.LocalDataSource.load (http://localhost:4200/1.chunk.js:22243:38)
Ok i got it by using like:
source: LocalDataSource;
constructor(private productService: ProductService,
private flashMessage: FlashMessagesService,
private router: Router,
http: Http)
{
this.source = new LocalDataSource();
}
onChange(categoryid) {
this.productService.getProductsOncategory(categoryid).subscribe(data => {
if (data.success) {
this.source.load(data.products);
console.log('Products obtained');
} else {
console.log('Not obtained!');
}
});
}
Had the same problem. It solved when i check all match columns and add the missing in table data. For example i delared a variable
Settings = {
....
columns: {
id: {
title: 'id',
show: false,
type: 'string',
},
name: {
title: 'name',
type: 'string',
},
//compare columns in json response in same variable declaration
//for your data table [source]
}
}
And in second case your table try get data from dataTableSource before full data loading, to avoid this use setTimeout(); method and set more time.
For Example:
getChildData(): Promise<any> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(this.childsList);
}, 4000);//<= increase this value
});
}
excuse me for my english))
I find interesting example how transfer data from one component to another component using Subject/Observable in Service:
http://plnkr.co/edit/yMBoVkxohwhPig5COgkU?p=preview
I find it similar to broadcast event from Angular 1.X. But I notice that subscribe to data changes can only component that inishiated data change. I need somehow modify this example to get data in one component after another component changed it. Console.log dos't show any error, but data-transfer not working. Can anyone help?
Service:
#Injectable()
export class ClientsService {
private _client$: Subject<Client>;
private _clients$: Subject<Client[]>;
constructor(private http: Http) {
this._client$ = <Subject<Client>>new Subject();
this._clients$ = <Subject<Client[]>>new Subject();
}
getClients(): Promise<Client[]> {
return this.http.get('api/Client')
.toPromise()
.then(res => {
this._clients$.next(res.json());
return res.json();
})
.catch(this.handleError);
}
get client$() {
return this._client$.asObservable();
}
get clients$() {
return this._clients$.asObservable();
}
clientChangeBroadcast(objClient: Client) {
this._client$.next(objClient);
}
clientsChangeBroadcast(arrClients: Client[]) {
this._clients$.next(arrClients);
}
private handleError(error: any): Promise<any> {
return Promise.reject(error.message || error);
}
First component:
#Component({
selector: 'app',
templateUrl: './app/app.component.html'
})
export class AppComponent implements OnInit {
clients: Client[];
constructor(public clientsService: ClientsService) {
this.clients = [];
}
ngOnInit() {
}
loadClients() {
this.clientsService.getClients().then(clients => {
this.clients = clients;
this.clientsService.clientsChangeBroadcast(clients);
});
}
selectClient(objClient: Client) {
this.clientsService.getClients();
this.clientsService.clientChangeBroadcast(objClient);
}
}
Second component:
export class TestComponent implements OnInit {
client: Observable<Client>;
clients: Observable<Client[]>;
constructor(private clinetsService: ClientsService) {
}
ngOnInit() {
//this.clinetsService.getClients();
this.client = this.clinetsService.client$;
this.clients = this.clinetsService.clients$;
this.clinetsService.client$.subscribe(value => {
// try to get changes here
});
this.clinetsService.clients$.subscribe(value => {
// try to get changes here
});
}
reLoadClients() {
this.clinetsService.getClients();
}
}
I try to get data changinf in 'Second component' after data was changed by 'First component'. When I click on button for 'selectClient' method in 'First component' I expect data transfer wia service and I catch changes ob 'Second component' -> it not working. When from 'Second component' I press button for 'reLoadClients' data transfer wia service and I catch changes in all subscribe functions on 'Second component'.
I'd like to understand how to make Hello.js work with React.js , especially the custom event handler hello.on
As I'm new to React.js, I don't understand how to bind non React events into the app flow.
I tried putting the event handler in the componentDidMount handler
handleClick(){
hello('twitter').login();
}
componentDidMount(){
hello.on('auth.login', function(auth) {
// Call user information, for the given network
hello(auth.network).api('/me').then(function(r) {
console.log(r);
});
});
hello.init({
'twitter' : 'J1jqqO50tcLtLx8Js0VDitjZW'
},
{
redirect_uri:'/',
oauth_proxy: 'https://auth-server.herokuapp.com/proxy'
});
}
thanks
And 3 years later:
You need a class for authentication, for example:
import * as React from "react";
import * as hello from "hellojs";
import { Event } from "../interfaces/Event";
export class Authentication extends React.Component<{}, { sendEvent: boolean }> {
constructor(public props, public context) {
super(props, context);
this.state = {
sendEvent: true
};
}
public login(network) {
hello.init({
aad: {
name: "Azure Active Directory",
oauth: {
version: 2,
auth: "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
grant: "https://login.microsoftonline.com/common/oauth2/v2.0/token"
},
// Authorization scopes
scope: {
// you can add as many scopes to the mapping as you want here
profile: "user.read",
offline_access: ""
},
scope_delim: " ",
login: p => {
if (p.qs.response_type === "code") {
// Let's set this to an offline access to return a refresh_token
p.qs.access_type = "offline_access";
}
},
base: "https://www.graph.microsoft.com/v1.0/",
get: {
me: "me"
},
xhr: p => {
if (p.method === "post" || p.method === "put") {
JSON.parse(p);
} else if (p.method === "patch") {
hello.utils.extend(p.query, p.data);
p.data = null;
}
return true;
},
// Don't even try submitting via form.
// This means no POST operations in <=IE9
form: false
}
});
hello.init(
{
aad: "ClientID"
},
{
redirect_uri: "YOUR REDIRECT_URI",
//redirect_uri: 'https://localhost:4321/temp/workbench.html',
scope: "user.read"
}
);
// By defining response type to code, the OAuth flow that will return a refresh token to be used to refresh the access token
// However this will require the oauth_proxy server
hello(network)
.login({ display: "none" })
.then(
authInfo => {
console.log(authInfo);
localStorage.setItem("logged", authInfo.authResponse.access_token);
},
e => {
console.error("Signin error: " + e.error.message);
}
);
}
//when the component is mounted you check the localstorage
//logged ==> undefined you call login and save a token in localstorage
//logged ==> with a token -> setEvent call a function that use graph api
public componentDidMount() {
let logged = localStorage["logged"];
if (logged === undefined) this.login("aad");
else {
if (this.state.sendEvent) {
this.props.setEvent(null);
this.props.setEvent(Event.GET_ALL_USERS);
}
}
}
public render() {
return null;
}
}
the file name is auth.tsx and you can call this class in the main react class:
export class mainClass extends React.Component{
......
......
private getEvent = (event) => {
this.setState({ event: event });
//HERE YOU recive the event when auth is ready
}
public render(){
<Authentication setEvent={this.getEvent} />
}
}