The data I am trying to access from the API is formatted like below:
{
“array1”:[
{"id”:1, ”someProperty”:”A"},
{"id":2, "someProperty”:”B”}
],
“array2”:[
{"id”:1, ”anotherProperty”:”foo”, ”lastProperty”:”foo2”},
{"id":2, "anotherProperty”:”bar”, ”lastProperty”:”bar2”}
]
}
The Dependencies class:
import { FirstArray } from './first-array';
import { SecondArray } from './second-array';
export class Dependencies {
constructor(
public array1: Array<FirstArray>,
public array2: Array<SecondArray>
) { }
}
The FirstArray class:
export class FirstArray {
constructor(
public id: number,
public someProperty: string
) { }
}
The SecondArray class:
export class SecondArray {
constructor(
public id: number,
public anotherProperty: string,
public lastProperty: string
) { }
}
My Dependencies service.ts file:
/** GET all Dependencies from the server */
getAllDependencies (): Observable<Dependencies[]> {
return this.http.get<Dependencies[]>(apiUrl).pipe(
tap(allDependencies => this.log('fetched allDependencies')),
catchError(this.handleError('getAllDependencies', []))
);
}
The component.ts file:
ngOnInit() {
this.getAllDependencies();
console.log("allDependencies:",this.allDependencies);
}
allDependencies: Dependencies[];
getAllDependencies(): void {
this.DependenciesService.getAllDependencies()
.subscribe(allDependencies => this.allDependencies = allDependencies);
}
When I try console.log(this.allDependencies) in the component file, the result is undefined. The data is retrieved from the API correctly- 'fetched allDependencies' is printed in the logs, and I can print the Dependencies object in the logs just fine by stringifying from the service file:
/** GET all Dependencies from the server */
getAllDependencies (): Observable<Dependencies[]> {
return this.http.get<Dependencies[]>(apiUrl).pipe(
tap(allDependencies => this.log(JSON.stringify(allDependencies))),
catchError(this.handleError('getAllDependencies', []))
);
}
My question: how can I access this data from my component file? I think I'm missing something in my data structures somewhere, or I have a Typescript-related error, but I am not sure.
The biggest issue you have is that within your component, the method that calls your service is void and doesn't return anything...
It doesn't really add any value, so remove it and access the data like this:
ngOnInit() {
this.DependenciesService.getAllDependencies()
.subscribe(allDependencies => {
this.allDependencies = allDependencies;
console.log(this.allDependencies); // multi-line with log.
});
}
Updated as per your comment:
Change your method from getAllDependencies(): void to getAllDependencies(): Observable<Dependencies[]> and call within ngOnOnit
getAllDependencies(): Observable<Dependencies[]> {
return this.DependenciesService.getAllDependencies();
}
ngOnInit() {
this.getAllDependencies().subscribe(.....);
}
Related
I am trying to pass some values as array on jobExport() collection and am getting an error Call to a member function jobsExport() on array. I understand that the collection need to populatet with modal collection value, but am trying to export multiple record(only record i select) from table , and to make this happend i thing i need to pass value as array from control to modal method, i have searched a loot to find a solution for this but i dont find anythin yet. Here is what i have done
Route
Route::any('export/jobs/{jobs}', [JobController::class, 'export']);
Pass data from vue to laravel
watch: {
selected: function(){
this.url = '/export/jobs/' + this.selected;
}
},
// After sending request on backend route will look like this
http://127.0.0.1:8000/export/jobs/1,2,4
Laravel controller
public function export($jobs)
{
return Excel::download(new JobsExport($jobs), 'jobs.xlsx');
}
Model Method
public function jobsExport()
{
return Job::with('templates', 'teams')
->whereHas('templates', function ($q) {
$q->where('id', $this->id);
})
->get();
}
JobExport
class JobsExport implements WithStyles, FromCollection, WithMapping, WithHeadings
{
use Exportable;
private $jobs;
public function __construct($jobs)
{
$this->jobs = $jobs;
}
public function collection()
{
return $this->jobs->jobsExport();
}
public function map($jobsExport): array
{
// dd($jobsExport->templates->first()->template_name);
return [
$jobsExport->id,
$jobsExport->templates->implode('template_name', ', '),
$jobsExport->job_completed,
];
}
/**
* #return \Illuminate\Support\Collection
*/
public function headings():array
{
return[
'Id',
'Template',
'Completed',
];
}
}
Is the $jobs an id? If so, make it $jobId
public function export($jobId)
{
// assuming you have Job model which holds the jobs table
$jobs = Job::where('id', $jobId)->get();
return Excel::download(new JobsExport($jobs), 'jobs.xlsx');
}
and in your export class
class JobsExport implements WithStyles, FromCollection, WithMapping, WithHeadings
{
use Exportable;
private $jobs;
public function __construct($jobs)
{
$this->jobs = $jobs;
}
public function collection()
{
// change this
//return $this->jobs->jobsExport();
// to
return $this->jobs;
}
public function map($jobsExport): array
{
// dd($jobsExport->templates->first()->template_name);
return [
$jobsExport->id,
$jobsExport->templates->implode('template_name', ', '),
$jobsExport->job_completed,
];
}
/**
* #return \Illuminate\Support\Collection
*/
public function headings():array
{
return[
'Id',
'Template',
'Completed',
];
}
}
I am new to json and angular. I am trying to access an API response using model. But it is giving me undefined when I try to access it.
Below is the json API returns
{
"Inventory App": {
"AnalyticsUI": "UP",
"BaseUI": "UP",
"PlanningUI": "UP",
"UploadUI": "DOWN"
}
}
My model definition is below
export class AppModel {
constructor(
public experience: AppList
) {}
}
export class AppList {
constructor(
public appName1: String,
public appName2: String,
public appName3: String,
public appName4: String,
public appName5: String
) {}
}
Below is my service call
import { AppModel } from './model/appList.model';
getAppStatus$(): Observable<AppModel> {
return this.http
.get('https://abc.xyc.com/AppController/AppsStatus')
.catch(this._handleError);
}
Below is the component where I am trying to access the API data.
export class MainComponent {
......
appList: AppModel;
.....
public _getAppStatus() {
this.appSub = this.api
.getAppStatus$()
.subscribe(
res => {
this.appList = res;
console.log(this.appList);
console.log(this.appList.experience);
},
err => {console.error(err); }
);
}
}
It is giving me undefined when I try to access this.appList.experience. Where as this.appList is printing the json result properly. Any help on this is much appreciated.
Console output :
Console output
As AJT and Khan stated, issue was property name not matching. Once I changed the property name to match the json response, I was able to get the values.
So basically what I want to achieve is watching/listening objects changing inside of array within an injectable service using setters and getters to manipulate it's data
eg
#Injectable()
export class StorageService {
protected items: Array<any> = [];
constructor(private storage: Storage) {
this.storage.ready().then(() => {
StorageService.getGetters().forEach((get) => {
this.storage.get(get).then(res => this.items[get] = res);
});
});
}
public static getGetters(): string[] {
return Object.keys(this.prototype).filter(name => {
return typeof Object.getOwnPropertyDescriptor(this.prototype, name)["get"] === "function"
});
}
get Storage() {
return this.storage;
};
ClearStorage() {
this.storage.clear();
}
protected Setter(key: string, value: any): void {
this.items[key] = value;
this.storage.set(key, value);
}
protected Getter(key: string): any {
return this.items[key];
}
set User(value: User) {
this.Setter('User', value);
}
get User(): User {
return this.Getter('User');
}
}
where User interface is :
export interface User {
id: number;
role_id: number;
name: string;
email?: string;
}
now in any component or service/provider I can DI my StorageService so I can access the User getter.
so:
storage.User.name = 'testing';
now the name is changed , but I have no way to track that , so I can update my storage!
to update my storage I would do:
storage.User.name = 'testing';
storage.User = storage.User;
which is working , but I need a way to listen to any changes happens to the object properties, so I can update my storage...
I searched alot , and all I can find is watching components #Input() , which is not working in my case.
Hopefully I made my point clear.
I have the following method in a service I've created:
getPost(nid: string): Observable<Post[]>{
let url = "http://test.co.uk/api/v1/basic/" + nid;
return this.http.get(url, {headers: this.headers}).map(res => res.json() as Post).catch(err => {
return Observable.throw(err);
});
}
And this is the class of my component:
export class PostDetailComponent implements OnInit {
posts: Post[] = [];
post: Post = new Post();
constructor(
private route: ActivatedRoute,
private postService: PostService
) { }
ngOnInit() {
this.route.params.switchMap((params: Params) => {
let nid = params ['nid'];
return this.postService.getPost(nid); }).subscribe(res => {
console.log(res)
this.post = res as Post;
}, err =>{
console.log(err);
});
}
}
The JSON feed looks like this(yes one object in the array):
[
{
"nid":"3",
"title":"When Unity meets Vuforia",
"body":"<p>Unless you have been living under a rock in the past 7 - ...",
"uid":"admin",
"path":"\/node\/3",
"field_article_image":"http:\/\/test.co.uk\/sites\/default\/files\/when-unity-meets-vuforia_0.jpg?itok=BGYaotay"
}
]
So in my template, if I print {{post}} I get [object Object] on the screen.
If I print {{post | json}} I get the row JSON feed.
And finally, if I print {{post.title}} or {{post?.title}} I don't get anything.
I also have a class Post that is looking like this:
export class Post{
constructor(
public nid?: string,
public title?: string,
public body?: string
public image?: string
){
}
}
Any hints?
You are assigning an array into what should be a single object. Copy the first element of the array into the post variable
this.post = res[0] as Post
Side note: It's incorrect to assign a raw object to a class instance. In this case, your this.post.constructor won't exist and this.post instanceof Post == false.
You could do Object.assign(this.post, res[0]) but you may need to clear existing properties if not all properties are always present.
I prefer to define object shapes as interfaces instead, then you would not have that problem because all the interface information is removed at runtime, whereas a class does emit some code instead of just doing static type checks at compilation time
I have the following code in typescript which calls a sharepoint rest api and gets lists items, however sharepoint internally saves thes user profiles with an id, instead of the name, so you can see number 9 actually should be a person name.
What I want is to replace that number 9 with my name, I already know what service I need to call, however I dont know how do it for each row of the json returned and to replace the 9 with the name returned.
My code is as follow:
/// <reference path="../../../typings/jquery/jquery.d.ts" />
/// <reference path="../../../typings/jquery.dataTables/jquery.dataTables.d.ts" />
import {
BaseClientSideWebPart,
IPropertyPaneSettings,
IWebPartContext,
PropertyPaneTextField
} from '#microsoft/sp-client-preview';
//import styles from './Pnpcrudsample.module.scss';
import ModuleLoader from '#microsoft/sp-module-loader';
import * as strings from 'pnpcrudsampleStrings';
import { IPnpcrudsampleWebPartProps } from './IPnpcrudsampleWebPartProps';
//import * as pnp from 'sp-pnp-js';
import MockHttpClient from './MockHttpClient';
import { EnvironmentType } from '#microsoft/sp-client-base';
require('jquery');
require('datatables');
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
Title?: string;
Id: number;
}
export interface IListItems{
value: IListItem[];
}
//Title,h7vv,v7nw,mczsId,mczsStringId,BooleanColumn
export interface IListItem {
Title: string;
h7vv: string;
v7nw: string;
mczsId: string;
BooleanColumn: string;
}
export default class PnpcrudsampleWebPart extends BaseClientSideWebPart<IPnpcrudsampleWebPartProps> {
//private container: JQuery;
//Default constructor, here we have to load css
public constructor(context: IWebPartContext) {
super(context);
ModuleLoader.loadCss('//cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css');
}
///Gets data from the mock, fake data
private _getMockListData(): Promise<IListItems> {
return MockHttpClient.get(this.context.pageContext.web.absoluteUrl)
.then((data: IListItem[]) => {
var listData: IListItems = { value: data };
return listData;
}) as Promise<IListItems>;
}
///Checks if the environment is local, then we will load data from mock, if not from the list
private _renderListAsync(): void {
// Local environment
if (this.context.environment.type === EnvironmentType.Local) {
this._getMockListData().then((response) => {
this._renderList(response.value);
});
}
else{
this._getListData()
.then((response) => {
this._renderList(response.value);
});
}
}
//Title,h7vv,v7nw,mczsId,mczsStringId,BooleanColumn
///Render list on the datatable
private _renderList(items: IListItem[]): void {
$('#example').DataTable({
data: items,
columns: [
{ "data": "Title" },
{ "data": "h7vv" },
{ "data": "v7nw" },
{ "data": "mczsId" },
{ "data": "BooleanColumn" }
]
});
}
///Get list data
private _getListData(): Promise<IListItems> {
return this.context.httpClient.get(this.context.pageContext.web.absoluteUrl + `/_api/web/lists/getbytitle('Lista')/items?$select=Title,h7vv,v7nw,mczsId,mczsStringId,BooleanColumn`)
.then((response: Response) => {
return response.json();
});
}
/// Generar contenido HTML
public render(): void {
debugger;
ModuleLoader.loadCss('//cdn.datatables.net/1.10.12/css/jquery.dataTables.min.css');
if (this.renderedOnce === false) {
this.domElement.innerHTML = `<table id="example" class="display" cellspacing="0" width="100%">
<thead>
<tr>
<th>Title</th>
<th>NumberColumn</th>
<th>DateColumn</th>
<th>PersonColumn</th>
<th>BooleanColumn</th>
</tr>
</thead>
</table>`;
}
this._renderListAsync();
}
//Property pane fields
protected get propertyPaneSettings(): IPropertyPaneSettings {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('listName', {
label: strings.ListNameFieldLabel
})
]
}
]
}
]
};
}
}
import { IListItem } from './PnpcrudSampleWebPart';
export default class MockHttpClient {
//Title,h7vv,v7nw,mczsId,mczsStringId,BooleanColumn
private static _items: IListItem[] =
[
{ Title: 'Mock List', h7vv: '1',v7nw :'01-01-2016',mczsId:'Luis Esteban Valencia',BooleanColumn:'Yes' },
{ Title: 'Mock List2', h7vv: '1',v7nw :'01-01-2016',mczsId:'Luis Esteban Valencia',BooleanColumn:'Yes' },
];
public static get(restUrl: string, options?: any): Promise<IListItem[]> {
return new Promise<IListItem[]>((resolve) => {
resolve(MockHttpClient._items);
});
}
}
The importan piece of the code above is: the _renderlist method which gets the data and BINDS it to a datatable (jquery plugin), I guess its there where I should plug the code to call the other service which is something like this:
https://mytenant.sharepoint.com/sites/devsitesc1/_api/web/getuserbyid(9)/title
No need of 2 REST calls here. The REST API call should look like...
https://mytenant.sharepoint.com/sites/devsitesc1/_api/web/lists/getByTitle('YourListTitle')/items?$select=Title,NumberColumn,...,PersonColumn/Title&$expand=PersonColumn
if you have any filter, you can add "$filter=..." also