Office UI Fabric React people picker not populating suggested drop down - reactjs

When I'm using the office ui fabric react component for people picker, it's not populating the suggested people in the dropdown.
Two errors that I'm getting are
Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
and
Exception in Layer.componentDidUpdate(): Exception in CommandButton.render(): TypeError: Cannot read property 'palette' of undefined
I've only been able to find this issue on github https://github.com/OfficeDev/office-ui-fabric-react/issues/1952, but there isn't much to go on. I am using office-ui-fabric-react version 4.5.1
The query is working from what I can see because I can console.log the results and it has people in there.
Here's what it looks like right now.
import * as React from 'react';
import { css,} from 'office-ui-fabric-react';
import { IReactRequestProps } from './IReactRequestProps';
import {
CompactPeoplePicker,
IBasePickerSuggestionsProps,
ListPeoplePicker,
NormalPeoplePicker
} from 'office-ui-fabric-react/lib/Pickers';
import { IPersonaProps } from 'office-ui-fabric-react/lib/Persona';
const suggestionProps: IBasePickerSuggestionsProps = {
suggestionsHeaderText: 'Suggested People',
noResultsFoundText: 'No results found',
loadingText: 'Loading'
};
import {
BaseComponent,
assign,
autobind
} from 'office-ui-fabric-react/lib//Utilities';
import { people } from './PeoplePickerExampleData';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { IPeopleDataResult } from './IPeopleDataResult';
import { IPersonaWithMenu } from 'office-ui-fabric-react/lib/components/pickers/PeoplePicker/PeoplePickerItems/PeoplePickerItem.Props';
import { IContextualMenuItem } from 'office-ui-fabric-react/lib/ContextualMenu';
import { SPHttpClient, SPHttpClientResponse } from '#microsoft/sp-http';
export interface IOfficeUiFabricPeoplePickerState {
currentPicker?: number | string;
delayResults?: boolean;
}
export interface IPeopleSearchProps {
JobTitle: string;
PictureURL: string;
PreferredName: string;
}
export default class ReactRequest extends React.Component<IReactRequestProps, IOfficeUiFabricPeoplePickerState> {
private _peopleList;
private contextualMenuItems: IContextualMenuItem[] = [
{
key: 'newItem',
icon: 'circlePlus',
name: 'New'
},
{
key: 'upload',
icon: 'upload',
name: 'Upload'
},
{
key: 'divider_1',
name: '-',
},
{
key: 'rename',
name: 'Rename'
},
{
key: 'properties',
name: 'Properties'
},
{
key: 'disabled',
name: 'Disabled item',
disabled: true
}
];
constructor() {
super();
this._peopleList = [];
people.forEach((persona: IPersonaProps) => {
let target: IPersonaWithMenu = {};
assign(target, persona, { menuItems: this.contextualMenuItems });
this._peopleList.push(target);
});
this.state = {
currentPicker: 1,
delayResults: false
};
}
public render(): React.ReactElement<IReactRequestProps> {
if (this.props.typePicker == "Normal") {
return (
<NormalPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
} else {
return (
<CompactPeoplePicker
onResolveSuggestions={this._onFilterChanged}
getTextFromItem={(persona: IPersonaProps) => persona.primaryText}
pickerSuggestionsProps={suggestionProps}
className={'ms-PeoplePicker'}
key={'normal'}
/>
);
}
}
#autobind
private _onFilterChanged(filterText: string, currentPersonas: IPersonaProps[], limitResults?: number) {
if (filterText) {
if (filterText.length > 2) {
return this.searchPeople(filterText, this._peopleList);
}
} else {
return [];
}
}
private searchPeople(terms: string, results: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
//return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
return new Promise<IPersonaProps[]>((resolve, reject) =>
this.props.spHttpClient.get(`${this.props.siteUrl}/_api/search/query?querytext='*${terms}*'&rowlimit=10&sourceid='b09a7990-05ea-4af9-81ef-edfab16c4e31'`,
SPHttpClient.configurations.v1,
{
headers: {
'Accept': 'application/json;odata=nometadata',
'odata-version': ''
}
})
.then((response: SPHttpClientResponse): Promise<{ PrimaryQueryResult: IPeopleDataResult }> => {
return response.json();
})
.then((response: { PrimaryQueryResult: IPeopleDataResult }): void => {
let relevantResults: any = response.PrimaryQueryResult.RelevantResults;
let resultCount: number = relevantResults.TotalRows;
let people = [];
let persona: IPersonaProps = {};
console.log(relevantResults);
console.log('really relevant');
if (resultCount > 0) {
relevantResults.Table.Rows.forEach(function (row) {
row.Cells.forEach(function (cell) {
//person[cell.Key] = cell.Value;
if (cell.Key === 'JobTitle')
persona.secondaryText = cell.Value;
if (cell.Key === 'PictureURL')
persona.imageUrl = cell.Value;
if (cell.Key === 'PreferredName')
persona.primaryText = cell.Value;
});
people.push(persona);
});
}
resolve(people);
console.log(people);
console.log("PEOPLE");
}, (error: any): void => {
reject(this._peopleList = []);
}));
}
private _filterPersonasByText(filterText: string): IPersonaProps[] {
return this._peopleList.filter(item => this._doesTextStartWith(item.primaryText, filterText));
}
private _removeDuplicates(personas: IPersonaProps[], possibleDupes: IPersonaProps[]) {
return personas.filter(persona => !this._listContainsPersona(persona, possibleDupes));
}
private _listContainsPersona(persona: IPersonaProps, personas: IPersonaProps[]) {
if (!personas || !personas.length || personas.length === 0) {
return false;
}
return personas.filter(item => item.primaryText === persona.primaryText).length > 0;
}
private _filterPromise(personasToReturn: IPersonaProps[]): IPersonaProps[] | Promise<IPersonaProps[]> {
if (this.state.delayResults) {
return this._convertResultsToPromise(personasToReturn);
} else {
return personasToReturn;
}
}
private _convertResultsToPromise(results: IPersonaProps[]): Promise<IPersonaProps[]> {
return new Promise<IPersonaProps[]>((resolve, reject) => setTimeout(() => resolve(results), 2000));
}
private _doesTextStartWith(text: string, filterText: string): boolean {
return text.toLowerCase().indexOf(filterText.toLowerCase()) === 0;
}
}

i got that error when using later versions of fabric. works fine with older versions,

Related

react-intl: formatMessage for array of string

I have several interfaces, and among these interfaces there is an interface for "displaying users", and there is a field called "Role", which represents an array of user roles,
And I want to translate this column, and it was actually translated through these lines:
tableDataMapper={(rows) => {
return rows?.map((row: any, index) => {
console.log('row: ', rows);
return {
...row,
roleNames: formatMessage({
id: formatMessage({ id: row?.roleNames }),
})
};
});
} }
But the problem is that if the array contains more than one element, it does not translate it, like this picture, it translates all lines except for the line indicated in red.
import { FunctionComponent, useContext } from 'react';
import user from '../../../../api/nuclearMedicineApi/services/User/index';
import Scaffold from '../../../common/scaffold';
import UserForm from './form/index';
import { userColumns } from './data';
import { selectMapper } from '../../../../utils/mappers';
import moment from 'moment';
import { indexFilters } from './filters';
import { useQuery } from 'react-query';
import {
AuthContext,
IAuthContext,
} from '../../../../contexts/auth-context';
import { FormattedMessage, useIntl } from 'react-intl';
interface UsersProps { }
const Users: FunctionComponent<UsersProps> = () => {
const { formatMessage } = useIntl();
const auth = useContext<IAuthContext>(AuthContext);
const filterOptionsData = useQuery('userFilterOptions', () =>
[{key: 'key', value: 0, label: 'label' }],
);
let userListColumns = userColumns;
userListColumns = auth.userData?.roleNames?.some(
(role) => role !== 'ADMIN',
)
? userListColumns.filter(
(item) => item.dataSelector !== 'roleNames',
)
: userListColumns;
return (
<>
<Scaffold
createFunc={user.userCreate}
getFunc={user.userGet}
getAllFunc={user.userGetAll}
filterColumns={indexFilters}
updateFunc={user.userUpdate}
deleteFunc={user.userCreate}
switchActivation
create
switchActivationFunc={user.userSwitchActivation}
tableColumns={userListColumns}
filterOptions={filterOptionsData.data}
dataName='user'
formContent={UserForm}
fullWidthFrom
exportToExcelFunc={user.userGetExcelReport}
defaultSizePaination={10}
pageSizeOptions={[10, 20, 50, 100]}
FormSubmitMapper={(data) => {
return {
...data,
password: data.password ?? null,
...selectMapper(['patientId', 'patient'], data),
};
} }
tableDataMapper={(rows) => {
return rows?.map((row: any) => {
console.log('row: ', rows);
return {
...row,
roleNames: formatMessage({
id: formatMessage({ id: row?.roleNames }),
})
};
});
} }
FromDataMapper={(data) => {
return {
...data,
lastModificationTime: moment(
new Date(data.lastModificationTime)
).format('YYYY-MM-DD, h:mm a'),
creationTime: moment(
new Date(data.creationTime)
).format('YYYY-MM-DD, h:mm a'),
};
} }
mainPermissionName='User' approveFunc={function (data: any): Promise<any> {
throw new Error('Function not implemented.');
} } rejectFunc={function (data: any): Promise<any> {
throw new Error('Function not implemented.');
} } />
</>
);
};
export default Users;
I assume that you want to display the translations of individual roles separated by commas (e.g if A translates to roleA and B translates to roleB, roleNames: ["A", "B"] should be displayed as "roleA, roleB").
Since you have roleNames: ["SystemAdmin", "NationalRegistry"], you could simply do roleNames.map(roleName => formatMessage({ id: roleName })).join(', ')

SPFx React Component Property Pane Update Lag

EDITED WITH CORRECT ANSWER
So I am customizing an SPFx component's property pane with a PropertyFieldSitePicker and a PropertyFieldListPicker. My issue is that the PropertyFieldMultiSelect lags by one selection when I select options from the PropertyFieldListPicker menu. However, if I make selections it will then update making me suspect it is a React state issue.
In the code below the following is the code logic
PropertyFieldListPicker('lists', {
// ... more props
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
}),
then
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (newValue !== oldValue && propertyPath === 'lists') {
this.loadPropertyPaneResources()
}
}
then
// this gets modified by loadPropertyPaneResources below
private _locationOptions: [];
protected loadPropertyPaneResources(): Promise<void> {
let listUrl = `...`
//... more code
return new Promise((resolve, reject) => {
this.context.spHttpClient.get(listUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => response.json())
.then((responseJSON: any) => {
this._locationOptions = responseJSON.value.map(item => {
if (item.displayName) {
return { key: item.Id, text: item.displayName }
}
return { key: item.Id, text: item.Title }
})
this.context.propertyPane.refresh()
resolve()
})
// ... more code
});
}
then
PropertyFieldMultiSelect('selectedLocations', {
key: 'selectedLocations',
label: 'Select Office Locations',
options: this._locationOptions, // from loadPropertyPaneResources above
selectedKeys: this.properties.selectedLocations
}),
FULL COMPONENT CLASS
export default class WorldClockWebPart extends BaseClientSideWebPart<IWorldClockProps> {
private _themeProvider: ThemeProvider
private _themeVariant: IReadonlyTheme | undefined
private _locationOptions: []
private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void {
this._themeVariant = args.theme
this.render()
}
protected loadPropertyPaneResources(): Promise<void> {
let listUrl = `${this.context.pageContext.web.absoluteUrl}/_api/lists/GetByTitle('World Clock Locations')/items`;
const { sites, lists } = this.properties
if (sites && sites[0] && sites[0].url && lists) {
listUrl = `${sites[0].url}/_api/lists(guid'${lists}')/items`;
}
return new Promise((resolve, reject) => {
this.context.spHttpClient.get(listUrl, SPHttpClient.configurations.v1)
.then((response: SPHttpClientResponse) => response.json())
.then((responseJSON: any) => {
this._locationOptions = responseJSON.value.map(item => {
if (item.displayName) {
return { key: item.Id, text: item.displayName }
}
return { key: item.Id, text: item.Title }
});
resolve();
})
.catch(error => {
console.error(error);
resolve();
});
});
}
protected onInit(): Promise<void> {
// Consume the new ThemeProvider service
this._themeProvider = this.context.serviceScope.consume(ThemeProvider.serviceKey)
// If it exists, get the theme variant
this._themeVariant = this._themeProvider.tryGetTheme()
// Register a handler to be notified if the theme variant changes
this._themeProvider.themeChangedEvent.add(this, this._handleThemeChangedEvent)
return super.onInit()
}
public render(): void {
const element: React.ReactElement<IWorldClockProps> = React.createElement(
WorldClock,
{
title: this.properties.title,
context: this.context,
displayMode: this.displayMode,
titlePlaceholder: this.properties.titlePlaceholder,
themeVariant: this._themeVariant,
updateProperty: (value: string) => {
this.properties.title = value
},
locations: [],
seeMoreUrl: this.properties.seeMoreUrl,
selectedLocations: this.properties.selectedLocations,
sites: this.properties.sites,
lists: this.properties.lists, // Stores the list ID(s)
}
)
ReactDom.render(element, this.domElement)
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement)
}
protected onPropertyPaneFieldChanged(propertyPath: string, oldValue: any, newValue: any): void {
if (newValue !== oldValue && propertyPath === 'lists') {
this.loadPropertyPaneResources()
}
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription,
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('seeMoreUrl', {
label: 'See More URL',
}),
PropertyFieldMultiSelect('selectedLocations', {
key: 'selectedLocations',
label: 'Select Office Locations',
options: this._locationOptions,
selectedKeys: this.properties.selectedLocations
}),
PropertyFieldSitePicker('sites', {
label: 'Select sites',
initialSites: this.properties.sites,
context: this.context,
deferredValidationTime: 500,
multiSelect: false,
onPropertyChange: this.onPropertyPaneFieldChanged,
properties: this.properties,
key: 'sites'
}),
PropertyFieldListPicker('lists', {
label: 'Select a list',
selectedList: this.properties.lists,
includeHidden: false,
orderBy: PropertyFieldListPickerOrderBy.Title,
disabled: false,
onPropertyChange: this.onPropertyPaneFieldChanged.bind(this),
properties: this.properties,
context: this.context,
onGetErrorMessage: null,
deferredValidationTime: 0,
key: 'listPickerFieldId',
webAbsoluteUrl: this.properties.sites[0].url
}),
],
},
],
},
],
}
}
protected get dataVersion(): Version {
return Version.parse('1.0')
}
}
References:
https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldListPicker/
https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldMultiSelect/
https://pnp.github.io/sp-dev-fx-property-controls/controls/PropertyFieldSitePicker/
I needed to call this.context.propertyPane.refresh() before I resolve the promise in loadPropertyPaneResources.

update observable object from array in observable object

I have documents id in the Information I am getting from service. I need documents Info to be attached to this parent information and return parent. Not able to return observables in loop.
The second switch map is working fine. The first is not executing if I return tInfo from map, it gives following error below.
Argument of type '(tInfo: { documents; documentsInfo:
any[]; }) => void' is not assignable to parameter of type '(value:
{ documents: any; documentsInfo: any[]; }, index: number) =>
ObservableInput'. Type 'void' is not assignable to type
'ObservableInput'
public transform(tId: any,name: string, args?: any): Observable<string> {
return this.sService.getTaxById(tId).pipe(
// tslint:disable-next-line: deprecation
switchMap((tInfo:{ documents ; documentsInfo: any [] }) => {
if (tInfo.documents) {
tInfo..documents.forEach(doc => {
return this.sService
.getFiles(doc.docId).pipe(
map((filesInfo: { FileName: ''; downloadUrl: '' }) => {
const fileObjnew =
{
docName: filesInfo.FileName,
downloadUrl: filesInfo.downloadUrl,
}
tInfo.documentsInfo.push(fileObjnew);
})
);
});
return of(taxInfo);
}
}),
// tslint:disable-next-line: deprecation
switchMap((Info: { cc: '' ; authority: '' ; cName: ''}) => {
if (Info.authority) {
const cc = taxInfo.cc;
return this.sService.getOrgs(cc).pipe(
map((orgsData: any) => {
console.log("Data============>", orgsData);
(orgsData || []).forEach(tax => {
if (orgsData.aid === tax.id) {
Info.cName = tax.parentName;
}
});
return Info;
})
);
}
}),
map((Info) => {
if (name === 'subsTemplate') {
return this.subsTemplate(Info);
}
})
);
}
In the first switchMap you have to return an observable in all code paths and to chain the getFiles sub-observables to your main observable, then return the observable combined by forkJoin.
You can try the following:
public transform(tId: any, name: string, args?: any): Observable<string> {
return this.sService.getTaxById(tId).pipe(
// tslint:disable-next-line: deprecation
switchMap((tInfo: { documents; documentsInfo: any[] }) => {
if (tInfo.documents) {
return forkJoin(
tInfo.documents.map((doc) =>
this.sService.getFiles(doc.docId).pipe(
map((filesInfo: { FileName: ''; downloadUrl: '' }) => {
const fileObjnew = {
docName: filesInfo.FileName,
downloadUrl: filesInfo.downloadUrl,
};
tInfo.documentsInfo.push(fileObjnew);
})
)
)
).pipe(mapTo(taxInfo));
}
return of(taxInfo);
}),
// tslint:disable-next-line: deprecation
switchMap((Info: { cc: ''; authority: ''; cName: '' }) => {
if (Info.authority) {
const cc = taxInfo.cc;
return this.sService.getOrgs(cc).pipe(
map((orgsData: any) => {
console.log('Data============>', orgsData);
(orgsData || []).forEach((tax) => {
if (orgsData.aid === tax.id) {
Info.cName = tax.parentName;
}
});
return Info;
})
);
}
return of(null);
}),
map((Info) => {
if (name === 'subsTemplate') {
return this.subsTemplate(Info);
}
})
);
}

React.js error: The service worker navigation preload request was cancelled before 'preloadResponse' settled

I have an issue with my React application (with Redux Saga), I'm getting the console error:
The service worker navigation preload request was cancelled before 'preloadResponse' settled. If you intend to use 'preloadResponse', use waitUntil() or respondWith() to wait for the promise to settle.
I see this error on the console only on Chrome, not in Firefox or Edge.
This error does not affect my application.
The following steps reproduce the error:
1. Main page upload.
2. Go to movie details page.
3. Go back to main page.
Main.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { mainActions } from '../../store/actions/actions';
import './Main.scss';
import { MoviesList, SearchPanel } from '../../components';
const propTypes = {};
const defaultProps = {};
class Main extends Component {
constructor(props) {
super(props);
this.handleSearchTextChange = this.handleSearchTextChange.bind(this);
this.handleLoadMoreButtonClick = this.handleLoadMoreButtonClick.bind(this);
this.handleMovieClick = this.handleMovieClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
const { moviesList } = this.props;
if (!moviesList || moviesList.length <= 0) {
this.getMovies(null, false);
}
}
handleLoadMoreButtonClick() {
this.getMovies(null, false);
}
handleMovieClick(e) {
if (e.target.className === 'movie') {
this.props.history.push(`/details/${e.currentTarget.dataset.id}`);
}
}
handleSearchTextChange(e) {
const { pageNumber, favoriteMoviesList } = this.props;
this.props.onSearchTextChange({
searchText: e.target.value,
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList
});
}
handleFavoriteMovieClick(e) {
const { id, name, posterId } = e.currentTarget.dataset;
const { moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: id, name: name, posterId: posterId },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
}
getMovies(updatedSearchText, isSearchChange) {
const { searchText, pageNumber, favoriteMoviesList } = this.props;
this.props.onLoadMovies({
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList,
updatedSearchText: isSearchChange ? updatedSearchText : searchText,
isSearchChange: isSearchChange
});
}
render() {
const { searchText, isLoadingMoreMovies, isPager, moviesList } = this.props;
return (
<div className="main-area">
<SearchPanel
searchText={searchText}
onSearchTextChange={this.handleSearchTextChange}
/>
<MoviesList
pageName='movies'
moviesList={moviesList}
isLoadingMoreMovies={isLoadingMoreMovies}
isPager={isPager}
onLoadMoreClick={this.handleLoadMoreButtonClick}
onMovieClick={this.handleMovieClick}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
</div>
);
}
}
Main.propTypes = propTypes;
Main.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
searchText: state.main.searchText,
pageNumber: state.main.pageNumber,
isLoadingMoreMovies: state.main.isLoadingMoreMovies,
isPager: state.main.isPager,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovies: (request) => dispatch(mainActions.loadMovies(request)),
onSearchTextChange: (request) => dispatch(mainActions.searchTextChange(request)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);
Details.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { detailsActions, mainActions } from '../../store/actions/actions';
import './Details.scss';
import { ActorsList, ButtonClick, CrewsList, FeaturesList, PageTitle, ProductionsList, Rating, Trailer } from '../../components';
import movieUtils from '../../utils/movie.utils';
const propTypes = {};
const defaultProps = {};
class Details extends Component {
constructor(props) {
super(props);
this.handleBackClick = this.handleBackClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
this.isFavorite = false;
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
if (this.props.moviesList.length <= 0) {
this.handleBackClick();
return;
}
const movieId = this.props.match.params.id;
if (!movieId) {
this.handleBackClick();
return;
}
this.props.onLoadMovieDetails(movieId);
this.updateIsFavorite(movieId);
}
numberWithCommas(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
updateIsFavorite(movieId) {
this.isFavorite = this.props.favoriteMoviesList.findIndex(movie => parseInt(movie.id) === parseInt(movieId)) > -1;
}
handleBackClick() {
this.props.history.push(`/`);
}
handleFavoriteMovieClick() {
const { movie, moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: movie.id, name: movie.title, posterId: movie.poster_path },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
this.updateIsFavorite(movie.id);
}
render() {
const { movie, youtubeKey, credits } = this.props;
if (!movie) {
return null;
}
const { adult, poster_path, budget, genres, homepage, imdb_id, original_language, original_title,
overview, popularity, production_companies, production_countries, release_date, revenue, runtime, spoken_languages,
status, tagline, title, video, vote_average, vote_count } = movie;
const genresText = genres.map(genre => genre.name).join(', ');
const countriesText = production_countries.map(country => country.name).join(', ');
const languagesText = spoken_languages.map(language => language.name).join(', ');
const featuresList = [
{ item: 'Release Date', value: release_date },
{ item: 'Budget', value: `$${this.numberWithCommas(budget)}` },
{ item: 'Revenue', value: `$${this.numberWithCommas(revenue)}` },
{ item: 'Length', value: `${runtime} minutes` },
{ item: 'Popularity', value: popularity },
{ item: 'Original Title', value: original_title },
{ item: 'For Adults', value: adult ? 'Yes' : 'No' },
{ item: 'Original Language', value: original_language },
{ item: 'Spoken Languages', value: languagesText },
{ item: 'Countries', value: countriesText },
{ item: 'Status', value: status },
{ item: 'Is Video', value: video ? 'Yes' : 'No' }
];
const linksList = [];
if (homepage) {
linksList.push({ id: 1, name: 'Homepage', url: homepage });
}
if (imdb_id) {
linksList.push({ id: 2, name: 'IMDB', url: `https://www.imdb.com/title/${imdb_id}` });
}
const actorsList = movieUtils.removeDuplicates(credits ? credits.cast ? credits.cast : null : null, 'name');
const crewsList = movieUtils.removeDuplicates(credits ? credits.crew ? credits.crew : null : null, 'name');
return (
<div>
<section className="details-area">
<PageTitle
pageName='details'
pageTitle='Details'
/>
<ul className="details-content">
<li className="details-left" style={{ backgroundImage: `url('https://image.tmdb.org/t/p/original${poster_path}')` }}></li>
<li className="details-right">
<h2>{title} ({release_date.substr(0, 4)})</h2>
<p className="genres">{genresText}</p>
<p className="description short">{tagline}</p>
<Rating
rating={vote_average}
votesCount={this.numberWithCommas(vote_count)}
/>
<p className="description full">{overview}</p>
<div className="extra">
<FeaturesList
featuresList={featuresList.slice(0, 5)}
linksList={null}
isFavorite={this.isFavorite}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
{youtubeKey && <Trailer
youtubeKey={youtubeKey}
/>}
</div>
</li>
<div className="extra-features">
<FeaturesList
featuresList={featuresList.slice(5, featuresList.length)}
linksList={linksList}
isFavorite={null}
onFavoriteMovieClick={null}
/>
<ProductionsList
productionsList={production_companies}
/>
</div>
</ul>
</section>
<section className="actors-area">
<PageTitle
pageName='actors'
pageTitle='Cast'
/>
<ActorsList
actorsList={actorsList}
/>
</section>
<section className="crew-area">
<PageTitle
pageName='crew'
pageTitle='Crew'
/>
<CrewsList
crewsList={crewsList}
/>
</section>
<ButtonClick
buttonText={'Back'}
buttonTitle={'Back'}
isLoading={false}
onClick={this.handleBackClick}
/>
</div>
);
}
}
Details.propTypes = propTypes;
Details.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
movie: state.details.movie,
youtubeKey: state.details.youtubeKey,
credits: state.details.credits,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovieDetails: (movieId) => dispatch(detailsActions.loadDetails(movieId)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Details);
What I already looked in:
Getting The service worker navigation preload request was cancelled before 'preloadResponse' settled
https://learn.microsoft.com/en-us/answers/questions/108004/getting-the-service-worker-navigation-preload-requ.html
https://support.google.com/mail/thread/4055804?hl=en
https://love2dev.com/pwa/service-worker-preload/
I tried to put this on Details.jsx page, but it didn't work:
self.addEventListener('fetch', event => {
event.respondWith(async function () {
// Respond from the cache if we can
const cachedResponse = await caches.match(event.request);
if (cachedResponse) return cachedResponse; // Else, use the preloaded response, if it's there
const response = await event.preloadResponse;
if (response) return response; // Else try the network.
return fetch(event.request);
}());
});
self.addEventListener('activate', event => {
event.waitUntil(async function () {
// Feature-detect
if (self.registration.navigationPreload) { // Enable navigation preloads!
console.log('Enable navigation preloads!');
await self.registration.navigationPreload.enable();
} return;
})();
});
How can I solve this issue? Thanks.
Had same error, even my iframe wasn't loading..whatever video you are using from youtube use nocookie/embed in url. It's working for me.
Try changing https://www.youtube.com/watch?v=i8eBBG46H8A to
https://www.youtube-nocookie.com/embed/i8eBBG46H8A
Hope nocookie & embed helps..!!

How to remove item from a generic Array in React Typescript?

Can someone show me how to remove an object in the newly created array? parameter "index" does not work well in this case as it is not really the index of the newly created array.
I am creating the new array in the onchange event.
Here I am including the full code. Just in case someone has got an idea.
import * as React from 'react';
import styles from './ListItems.module.scss';
import { IListItemsProps } from './IListItemsProps';
import { escape } from '#microsoft/sp-lodash-subset';
import {DropdownBasicExample} from './DropdownExample'
import { IDropdownOption, DropdownMenuItemType } from 'office-ui-fabric-react';
import { DropdownBasicExample2 } from './Dropdown2.Basic.Example';
export interface IListItemsState{
selectedItems:IDropdownOption[];
selectedSite:IDropdownOption;
}
export default class ListItems extends React.Component<IListItemsProps, IListItemsState> {
private myWeb:IDropdownOption;
constructor(props){
super(props);
this.state = {
selectedItems:[],
selectedSite:null
}
}
private sites = [
{ key: 'Header', text: 'Actions', itemType: DropdownMenuItemType.Header },
{ key: 'A', text: 'Site a', title: 'I am Site a.' },
{ key: 'B', text: 'Site b' },
{ key: 'C', text: 'Site c' },
{ key: 'D', text: 'Site d' },
{ key: 'E', text: 'Site e' },
{ key: 'F', text: 'Site f' },
{ key: 'G', text: 'Site g' },
{ key: 'H', text: 'Site h' },
{ key: 'I', text: 'Site i' },
{ key: 'J', text: 'Site j' }
];
private loadSites= (): Promise<IDropdownOption[]> => {
return new Promise<IDropdownOption[]>((resolve: (sites: IDropdownOption[]) => void, reject: (error: any) => void) => {
setTimeout(() => {
resolve(this.sites);
}, 1000);
});
}
private onChanged = (item: IDropdownOption, index?: number): void => {
let mySelectedItems = [...this.state.selectedItems];
if (item.selected) {
mySelectedItems.push(item);
} else {
mySelectedItems = mySelectedItems.filter(selectedItem => selectedItem !== item);
}
this.setState({
selectedItems: mySelectedItems
});
console.log(mySelectedItems);
}
public render(): React.ReactElement<IListItemsProps> {
const {selectedSite} = this.state;
return (
<div className={styles.listItems}>
<DropdownBasicExample loadOptions={this.loadSites} onChanged={this.onChanged} />
<div id="showItems"></div>
<ul>{
this.state.selectedItems.map((site:IDropdownOption)=> {
return <li>{site.text}</li>
})
}
</ul>
<div>selected Site {
selectedSite ? selectedSite.key: "is empty"
}</div>
</div>
);
}
}
DropdownBasicExample2
import * as React from 'react';
import { PrimaryButton } from 'office-ui-fabric-react/lib/Button';
import { Dropdown, IDropdown, DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import './Dropdown.Basic.Example.scss';
import { BaseComponent, createRef, IBaseProps } from 'office-ui-fabric-react';
export interface IDropdownBasicExample2State{
selectedItem?: IDropdownOption;
selectedItems: IDropdownOption[];
options: IDropdownOption[];
}
export interface IDropdownBasicExample2Props extends IBaseProps{
onChanged?: (option: IDropdownOption, index?: number) => void;
Options: IDropdownOption[];
}
export class DropdownBasicExample2 extends BaseComponent<IDropdownBasicExample2Props,IDropdownBasicExample2State> {
private _basicDropdown = createRef<IDropdown>();
private alphas:IDropdownOption[];
private array2: Array<IDropdownOption>;
constructor(props: IDropdownBasicExample2Props) {
super(props);
this.state = {
selectedItem: null,
selectedItems: [],
options:[]
};
}
componentDidMount(){
}
public render() {
const { selectedItem, selectedItems } = this.state;
return (
<div className="docs-DropdownExample">
<Dropdown
placeHolder="Select options"
label="Multi-Select controlled example:"
selectedKey={selectedItem ? selectedItem.key : undefined}
key={selectedItem ? selectedItem.key : undefined}
onChanged={this.onChangeMultiSelect}
multiSelect
options={this.props.Options}
/>
</div>
);
}
public onChangeMultiSelect = (item: IDropdownOption,index:number): void => {
this.props.onChanged(item,index);
};
}
You could filter out the item from the array.
private onChanged = (item: IDropdownOption, index?: number): void => {
let mySelectedItems = [...this.state.selectedItems];
if (item.selected) {
mySelectedItems.push(item);
} else {
mySelectedItems = mySelectedItems.filter(
selectedItem => selectedItem !== item
);
}
this.setState({
selectedItems: mySelectedItems
});
};
Give this a try. Remove items based on a property. In this case I am using the key.
private onChanged = (item: IDropdownOption, index?: number): void => {
let mySelectedItems = [...this.state.selectedItems];
if (item.selected) {
mySelectedItems.push(item);
} else {
mySelectedItems = mySelectedItems.filter(selectedItem => selectedItem.key !== item.key);
}
this.setState({
selectedItems: mySelectedItems
});
}

Resources