can get data out of http request - frontend

i have a problem receiving data to variable.
this works:
this.http.get(some_url).subscribe(
data => {
console.log(JSON.parse(data['_body']))
});
but if i try to get the value to a variable instead of printing it, it does not work:
this.http.get(some_url).subscribe(
data => {
this.var = JSON.parse(data['_body'])
});
i need your help, i tried everything.
Thanks!

This doesn't seem to be an angular 2 issue. Can you try the following steps to debug?
Check the console (F12) for any errors while making the GET call
Print and store the returned the data in the variable
Are there any lines above the variable assignment line that you have not posted?
I've created a plunker where you can see the variable assignment in action
https://embed.plnkr.co/MEHTZ92HgZhEbUZlBELQ/
the app.component.ts is as follows
import { Component } from '#angular/core';
import { Http } from '#angular/http';
#Component({
selector: 'my-app',
template: `
<div>
<p>Content: {{ content }}</p>
</div>
`,
})
export class AppComponent {
content: string;
constructor(private http: Http) {
this.http.get('https://jsonplaceholder.typicode.com/posts/1').subscribe(
data => {
this.content = data
});
}
}
And the result I get is
Content: Response with status: 200 OK for URL: https://jsonplaceholder.typicode.com/posts/1
Of course, one shouldn't use the constructor for network calls and similar heavy stuff and should use ngOnInit instead, but just for the sake of example I've made the call in the constructor

Related

Can't get html element using js file in SPFX

I am trying to build dynamic content from a SharePoint list using SPFX. I'd like to use jQuery to build an accordion view of the data. The issue is that I can't even seem to get the element once the page is rendered.
In my code I am requiring a file called ota.js with the following code:
console.log('Start');
function otaExpand(){
console.log('otaExpand Function Called');
let spListContainer = document.getElementById('spListContainer');
console.log(spListContainer);
}
window.addEventListener("load", otaExpand());
In my ts file this is my render method:
public render(): void {
this.domElement.innerHTML = `
<div>
<div id="spListContainer">TEST</div>
</div>
`;
//this._renderListAsync();
//($('.accordion', this.domElement) as any).accordion();
}
When I review the console, I get my messages, but the element itself comes back as null.
console.log
I am using SharePoint 2019 on premise with the following configuration.
+-- #microsoft/generator-sharepoint#1.10.0
+-- gulp-cli#2.3.0
`-- yo#2.0.6
node --version
v8.17.0
I should also mention I am using TypeScript with no JavaScript framework.
Does anyone know why I can't access this element from my js file?
Thanks!
My overall goal is to call list data and apply an accordion style to it (https://jqueryui.com/accordion), but I can't even get passed capturing the element to change it.
I've tried calling my code from a js file as well as trying to put the code directly in the html. Neither worked.
OK, I finally figured out what I was doing wrong. I was calling my jQuery in the render() method rather than in _renderList where this.domElement actually makes sense.
Here's my code in case anyone wants to avoid the pain I put myself through. This allows you to specify a list in the site and you just need to add the fields you want to display.
import { Version } from '#microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneChoiceGroupOption,
IPropertyPaneConfiguration,
PropertyPaneChoiceGroup,
PropertyPaneCustomField,
PropertyPaneTextField
} from '#microsoft/sp-webpart-base';
import { escape } from '#microsoft/sp-lodash-subset';
import styles from './GetSpListItemsWebPart.module.scss';
import * as strings from 'GetSpListItemsWebPartStrings';
import {
SPHttpClient,
SPHttpClientResponse
} from '#microsoft/sp-http';
import * as jQuery from 'jquery';
import 'jqueryui';
import { SPComponentLoader } from '#microsoft/sp-loader';
import PropertyPane from '#microsoft/sp-webpart-base/lib/propertyPane/propertyPane/PropertyPane';
export interface IGetSpListItemsWebPartProps {
title: string;
description: string;
listField: string;
}
export interface ISPLists {
value: ISPList[];
}
export interface ISPList {
ID: string;
Title: string;
Website: {
Description : string,
Url : string
};
Description : string;
}
export default class GetSpListItemsWebPart extends BaseClientSideWebPart<IGetSpListItemsWebPartProps> {
private _getListData(): Promise<ISPLists> {
return this.context.spHttpClient.get(this.context.pageContext.web.absoluteUrl + "/_api/web/lists/GetByTitle('" + this.properties.listField + "')/Items",SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => {
return response.json();
});
}
private _renderListAsync(): void {
this._getListData()
.then((response) => {
this._renderList(response.value);
})
.catch(() => {});
}
private _renderList(items: ISPList[]): void {
let listData = `
<h1>${this.properties.title}</h1>
<h2>${this.properties.description}</h2>
<div class="accordion">
`;
items.forEach((item: ISPList) => {
let Description : string;
item.Description ? Description = item.Description : Description = "";
listData += `
<h3> ${item.Title}</h3>
<div>
<table>
<tr>
<td>OTA URL</td>
<td>${item.Website.Description}</td>
</tr>
<tr>
<td>Description</td>
<td>${Description}</td>
</tr>
</table>
</div>
`;
});
listData += '</div>';
this.domElement.innerHTML = listData;
const accordionOptions: JQueryUI.AccordionOptions = {
animate: true,
collapsible: true,
icons: {
header: 'ui-icon-circle-arrow-e',
activeHeader: 'ui-icon-circle-arrow-s'
}
};
jQuery('.accordion', this.domElement).accordion(accordionOptions);
}
public render(): void {
this._renderListAsync();
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('title',{
label: strings.TitleFieldLabel
}),
PropertyPaneTextField('description', {
label: strings.DescriptionFieldLabel
}),
PropertyPaneTextField('listField', {
label: strings.ListFieldLabel
})
]
}
]
}
]
};
}
public constructor() {
super();
SPComponentLoader.loadCss('//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css');
}
}
Your code from the "ota.js" file is probably called before your HTML is initialized (i.e. before the "render()" function is executed). To make sure this is the case, you could add log to the "render()" function to see when it's called.
In other words, "window.load" event happens long before "render()" function is called. This is how web parts are loaded - dynamically after full load of the page. Or "window.load" does not happen at all - web parts may be loaded by the user when using the page designer, i.e. without page reload.
To fix the issue, you should get the element after it's created, i.e. after the "render()" function creates the element you are trying to get.

ionViewWillEnter doesn't work on entering the page

As the title suggests, my function doesn't trigger once I access the page itself. I have a button that is supposed to redirect me to another page, yet the page itself doesn't load nor the function. The code at the moment looks like this:
import {Component} from "#angular/core";
import {NavController, AlertController} from "ionic-angular";
#Component({
selector: 'page-patch-notes',
templateUrl: 'patch-notes.html'
})
export class PatchNotes {
constructor(private nav: NavController, private alertCtrl: AlertController) {
}
ionViewWillEnter() {
let alert = this.alertCtrl.create({
title: 'Patch Notes',
message: "Introduceti adresa de email pentru a va trimite un link de resetare parola.",
buttons: [
{
text: 'Anulati',
handler: data => {
console.log('Cancel clicked');
}
},
{
text: 'Ok',
handler: data => {
console.log('Ok clicked');
}
},
]
});
alert.present();
}
}
It's likely that the alert controller is created and displayed before the page is even loaded. Ionic lifecycles states that his hook fires
between the "Begin Page Transition" and "Page Fully Transitioned" stages.
I have had a lot of success tying this kind of logic to ngOnInit. You will need to update your class def to export class PatchNotes implements OnInit. The fact that this wasn't done suggests that fransicso neto's suggestion may be accurate as well. If you aren't already, it's always a good idea to generate pages using the Ionic CLI.

Angular 7 ngx-translate change run time transaltion without refresh page

Notes: I tired all questions & answers related to this topic.
I want to Translate Typescript variable Value without refresh page on change language Dropdown .
I trying To change the language-wise data change. I success to change to HTML Bind: value on dropdown value change but not update TypeScript Bind: value.
i use ngx-translate
I referer Links: but not success
angular-ngx-translate-usage-in-typescript
ngx-translate-in-ts-file-angular
ngx-translate-with-dynamic-text-on-ts-file
components.ts
import { Component, OnInit } from '#angular/core';
import { TranslateService } from '#ngx-translate/core';
#Component({
selector: 'app-translate',
templateUrl: './translate.component.html',
styleUrls: ['./translate.component.css']
})
export class TranslateComponent implements OnInit {
typeScriptvalue: string;
simpleProducts:any[]=[ {
name:'English',
id:'en'
},
{
name:'French',
id:'fr'
}];
constructor(private translate: TranslateService) {
this.typeScriptvalue = this.translate.instant('HOME.TITLE');
}
ngOnInit(): void {
}
changeevent(e)
{
console.log(e);
this.translate.use(e.value);
}
}
component.html
<label><b> HTML Bind</b></label> : <div>{{ 'HOME.TITLE' | translate }}</div> <br>
<label><b>TypeScript Bind</b></label> : <div>{{ typeScriptvalue }}</div> <br>
<label>
Change language : <div class="dx-field-value">
<dx-select-box [dataSource]="simpleProducts" displayExpr="name" valueExpr="id" (onValueChanged)="changeevent($event)"></dx-select-box>
</div>
</label>
After long research I have finally got the best solution.
You can reassign the Typescript variable on the subscriber method. use method
changeevent(e)
{
console.log(e);
this.translate.use(e.value).subscribe(data => {
this.typeScriptvalue = this.translate.instant('Home.Title');
});
}

Angular production error: Property does not exist on type 'object'

I have an Angular 7 app that is retrieving data from two separate endpoints:
http://localhost:1337/sms
http://localhost:1337/total
I can successfully make a GET request to these endpoints in development. However, I get the following error when I run ng build --prod:
ERROR in src/app/app.component.html(20,29): : Property 'total' does not exist on type 'object'.
As a test I temporarily removed {{ total.total }} from app.component.html, ran ng build --prod again and it worked.
Is this not the right way to make GET requests to two separate endpoints or am I doing something else incorrectly, perhaps in my Node server file?
app.component.ts
import { Component, OnInit } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
signees: object;
total: object;
constructor(private http: HttpClient){}
ngOnInit(): void {
this.http.get('http://localhost:1337/sms').subscribe(
data => {
this.signees = data;
}
);
this.http.get('http://localhost:1337/total').subscribe(
data => {
this.total = data;
}
);
}
}
Relevant app.component.html code
<section class="page-section mx-auto">
<h3 class="text-center">{{ total.total }} people have signed the petition</h3>
<div class="container">
<div class="row">
<div class="col-sm-6 col-lg-3"
*ngFor="let signee of signees; index as i">
<div class="card">
<div class="card-body">
<p class="h2">{{ signee.name }}</p>
<ul class="signee-meta text-muted">
<li>#{{ i + 1 }}</li>
<li>{{ signee.date }}</li>
</ul>
</div>
</div>
</div>
</div><!-- row -->
</div><!-- container -->
</section>
/total endpoint (MongoDB)
app.get('/total', (req, res) => {
collection.countDocuments({}, function(err, num) {
assert.equal(null, err);
res.send({total: num});
});
});
EDIT (added data structure)
Data structure (MongoDB)
{
"_id" : ObjectId("5c61e0b658261f10280b5b17"),
"name" : "Bill Kickok",
"number" : "+14950395584",
"date" : "2/11/19"
}
This error is thrown when you run ng build --prod because behind the scenes this kind of build proccess works with Ahead Of Time compilation.
Here's what happens on AOT based on angular documentation.
Detect template errors earlier
The AOT compiler detects and reports template binding errors during
the build step before users can see them.
You get that error because you try to render a property of total object while you have declared total as object.
In order to get rid of this error you should either create an interface for this variable. e.g.
export interface Total {
total: number
// any other properties total might include
}
Then use this interface for type definition in your component like this:
total: Total
In case you don't want to create an interface - which is a bad practice - you can define total as any (total: any).
Lastly, directly making the http requests in your component is also a bad practice. You should create a service, then add those methods which are responsible for communicating with your backend, then inject that service in your component and call that method.
I would advise you to take further look at angular documentation.
If possible, it would be a good idea to strongly type these properties, so instead of:
signees: object;
total: object;
If would be:
signees: Signee[];
total: Total;
Where Signee and Total would be interfaces:
export interface Signee {
id: number;
name: string;
date: string;
// ...
}
export interface Total{
id: number;
total: number;
// ...
}
NOTE: The above would match the JSON structure returned in data (which is why someone asked what the structure of your data looked like).
And if total is just a single number you are receiving back, then it would just be:
total: number;
And you would just bind to total, not total.total.
You can then use this strong typing when you send the request to ensure that the response is appropriately shaped:
this.http.get<Signee[]>('http://localhost:1337/sms').subscribe(
data => {
this.signees = data;
}
);
Notice the generic parameter specified in the code above.
you need start your object inside of constructor.
ex:
constructor(private http: HttpClient){
total = new Total();
}
Total is your class. This is recomendate in angular.io. Start your VAR inside constructor.

center paper-dialog upon opening

I'm trying to create a simple login window using Angular 2 and Polymer 1.0.2.
It's basically a paper-dialog (login window) with content. The dialog however is not positioned in the center of the screen, see this bugreport Dialog not centered until window resize #36:
The issue suggests calling the notifyResize() method on the paper-dialog. But I've no clue as how to refer to the paper-dialog instance in my angular 2/polymer class.
Somehow the import {PaperDialog} is not resolved, but looking in the paper-dialog.html makes me wondering if such an import is possible at all.
import {Component, View} from 'angular2/angular2';
import {PaperDialog} from 'bower_components/paper-dialog/paper-dialog';
#Component({
template: `
<paper-dialog open>
...
</paper-dialog>
`,
selector: 'login-window',
directives : [PaperDialog]
})
export class LoginWindow {
email: string;
password: string;
constructor(){
this.email = '';
this.password = '';
// Where and how to call the PaperDialog child's notifyResize() method
}
}
Note that I'm not opening the dialog programmatically (fix described here).
This solution uses the /deep/ selector that is deprecated.
And it shouldn't be fixed by applying some css, should it?
Instead of having my code fix the paper-dialog behaviour's code, it's way better to fix the problem itself.
Add the call this.notifyResize(); to the _onIronOverlayOpened method in the paper-dialog-behavior.html source.
...
_onIronOverlayOpened: function() {
if (this.modal) {
document.body.addEventListener('focus', this._boundOnFocus, true);
this.backdropElement.addEventListener('click', this._boundOnBackdropClick);
}
this.notifyResize(); // Added this line
},
...
Although this resolves my simple paper-dialog center problem, I can not oversee consequences for other elements and code yet.
You could also fix it in the following manner:
Within an angular2 Component (that wraps the paper-dialog element) you could so something like this (Typescript example):
interface PaperDialog extends HTMLElement {
notifyResize(): void;
}
#Component({
selector: 'login'
})
#View({
templateUrl: 'app/components/ts-login-window/ts-login-window.html'
})
export class LoginWindow {
email: string;
password: string;
dialogWindow: PaperDialog;
private bindIronOverlayOpened: EventListenerObject;
constructor(elementRef: ElementRef){
this.dialogWindow = elementRef.nativeElement.children[0];
this.bindIronOverlayOpened = this.ironOverlayOpened.bind(this);
this.dialogWindow.addEventListener('iron-overlay-opened', this.bindIronOverlayOpened);
}
ironOverlayOpened(event: Event) {
this.dialogWindow.notifyResize();
}
onDestroy() {
this.dialogWindow.removeEventListener('iron-overlay-opened', this.bindIronOverlayOpened);
}
}
Once the paper-dialog has been opened (by the event iron-overlay-opened) you could trigger the notifyResize() event on the dialog box. This in turn fixes the alignment problem.

Resources