ionViewWillEnter doesn't work on entering the page - node.js

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.

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.

can get data out of http request

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

Get link of an image in react-photo-gallery?

I'm still a beginner in reactJS (using nodeJS backend) and I have to create a website to manage my collections. I don't know if what I'm going to ask you is feasible, but it probably is.
So I'm using a react component, react-photo-gallery. It's a component where you can use url links and it mixes them together to create a beautiful gallery.
https://github.com/neptunian/react-photo-gallery
I'm using nodeJS to get the information from the database, where I get the urls of all the pictures. For example I have a collection of cards, and an url of the image which represents the collection. What I want to do is get the link of the picture that I'm clicking on so I can use it in another component.
import React from 'react';
import { render } from 'react-dom';
import Gallery from 'react-photo-gallery';
import Photo from './Photo';
class PhotoGallery extends React.Component {
constructor(props){
super(props);
this.onClick = this.onClick.bind(this);
this.state = {
urlImages: []
};
}
async componentDidMount() {
var getUrlImages = 'http://localhost:3004';
const response = await fetch(getUrlImages+"/getUrlImages");
const newList = await response.json();
this.setState(previousState => ({
...previousState,
urlImages: newList,
}));
}
galleryPhotos() {
if(this.state.urlImages) {
return this.state.urlImages.map(function(urlimage) {
return { src: urlimage.urlimage, width: 2, height: 2 }
})
}
}
onClick() {
alert(this.galleryPhotos().value);
}
render() {
return (
<Gallery axis={"xy"} photos={this.galleryPhotos()} onClick={this.onClick}/>
)
}
}
const photos = [];
export default PhotoGallery;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
Basically what I want to do is get the source link of the picture in the onClick function. Is that possible?
Thanks in advance!
Check the onClick event.
onClick(event) {
alert(event.target.src)
}
The DEMO
The onClick event of the Gallery component has a number of arguments:
the event
an object containing the selected index and the original photo object
You can use this in your onClick handler:
onClick(e, obj) {
const src = obj.photo.src
// do whatever you need with the src (setState, etc)
}

Disable the side menu's swipe to open gesture for Login page (or any page) in Ionic 2

I'm new to Ionic 2 & Angular2 and I have downloaded a new Ionic template with the following command
Ionic start appname sidemenu --v2 --ts
For this particular solution I have added a login page to validate a user. Once the validation succeeds the user will be navigated to the menu page which uses the side menu.
As the solution is based on the sidemenu template, the side menu is showing on the login page whenever the user swipes left.
So can somebody please guide me to rectify this mistake and stop the side menu from showing when the view is swiped.
My code
App.ts file
import {App, IonicApp, Platform,MenuController} from 'ionic-angular';
import {StatusBar} from 'ionic-native';
import {HelloIonicPage} from './pages/hello-ionic/hello-ionic';
import {ListPage} from './pages/list/list';
import {HomePage} from './pages/home/home';
#App({
templateUrl: 'build/app.html',
config: {} // http://ionicframework.com/docs/v2/api/config/Config/
})
class MyApp {
// make HelloIonicPage the root (or first) page
rootPage: any = HomePage;
pages: Array<{title: string, component: any}>;
constructor(
private app: IonicApp,
private platform: Platform,
private menu: MenuController
) {
this.initializeApp();
// set our app's pages
this.pages = [
{ title: 'Hello Ionic', component: HelloIonicPage },
{ title: 'My First List', component: ListPage }
];
}
initializeApp() {
this.platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
StatusBar.styleDefault();
});
}
openPage(page) {
// close the menu when clicking a link from the menu
this.menu.close();
// navigate to the new page if it is not the current page
let nav = this.app.getComponent('nav');
nav.setRoot(page.component);
}
}
app.html file
<ion-menu side-menu-content drag-content="false" [content]="content">
<ion-toolbar>
<ion-title>Pages</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<button ion-item *ngFor="#p of pages" (click)="openPage(p)">
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav id="nav" [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>
Homepage.ts file (login page in this case).
import {Page, Events,Alert,NavController,Loading,Toast,Storage,LocalStorage,SqlStorage} from 'ionic-angular';
import { FORM_DIRECTIVES, FormBuilder, ControlGroup, Validators, AbstractControl } from 'angular2/common';
import {HelloIonicPage} from '../hello-ionic/hello-ionic';
import {NgZone} from 'angular2/core';
#Page({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage {
public Uname :string;
public usrvalid:boolean;
public usrpwd :boolean;
public usrpwdlength:boolean;
public usrvalidlength:boolean;
public isUnchanged:boolean;
public usrpwdzero:boolean;
public usrvaliddigits:boolean;
rootpage:any;
public Upwd:string;
constructor(public nav:NavController) {
this.nav=nav;
this.isUnchanged=true;
var mediumRegex = new RegExp("^(((?=.*[a-z])(?=.*[A-Z]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[A-Z])(?=.*[0-9])))(?=.{6,})");
// rootPage: any = HomePage;
}
}
I think the drag-content directive is used in ionic 1, for Ionic 2 what you can do is disable it from within your page class file.
You can do this by importing the MenuController provider from ionic-angular and then call the .swipeEnable(shouldEnableBoolean, menuId) method to disable the swipe gesture within your page's class (this is also documented here).
Your login controller should be something like this...
import {Page, MenuController} from 'ionic-angular';
#Page({
templateUrl: 'build/pages/home/home.html'
})
export class HomePage {
constructor(public menu: MenuController) {
this.menu.swipeEnable(false);
}
}
If you have multiple menus and each one has an id then you can target a specific menu like this...
this.menu.swipeEnable(false, `menuId`);
You can disable/enable sidemenu at any time at any page by calling
$ionicSideMenuDelegate.canDragContent(false)
e.g:
angular.module('ABC').controller('xyzCtrl', function($scope, $ionicSideMenuDelegate) {
$ionicSideMenuDelegate.canDragContent(false)
});

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