iTwin / itwinjs-core

Monorepo for iTwin.js Library
https://www.itwinjs.org
MIT License
623 stars 211 forks source link

How to call presentation by calling Presentation.initialise #2235

Closed kiranshetty07061999 closed 3 years ago

kiranshetty07061999 commented 3 years ago

Hi there,

I am trying to get the EcInstanceId of the components of the model upon click. I tried implementing the same by using the following set of codes

export function SelectionOfComponentsData() {

React.useEffect(() => {

  Presentation.selection.selectionChange.addListener(_onSelectionChanged);

}

);

const _onSelectionChanged = async (evt: SelectionChangeEventArgs, selectionProvider: ISelectionProvider) => { const selection = selectionProvider.getSelection(evt.imodel, evt.level); console.log(selection) };

I have written this set of codes in a different file and have imported it in my App.tsx.... But when i run my code , I get the following error

Screenshot 2021-09-14 at 9 58 42 AM

How do i resolve this? I have pasted my App.tsx and SelectionOfComponents here

App.tsx

/*---------------------------------------------------------------------------------------------

import "./App.scss";

import { BrowserAuthorizationClientConfiguration } from "@bentley/frontend-authorization-client"; import { DisplayStyleSettingsProps } from "@bentley/imodeljs-common"; import { FitViewTool, IModelApp, IModelConnection, ScreenViewport, StandardViewId,IModelAppOptions } from "@bentley/imodeljs-frontend"; import { Viewer } from "@itwin/web-viewer-react"; import React, { useEffect, useState } from "react"; import { Header } from "./Header"; import { history } from "./history"; import {ISelectionProvider, Presentation, SelectionChangeEventArgs , PresentationManagerProps } from "@bentley/presentation-frontend"; import { ChangedValueState, IModel } from "@bentley/imodeljs-common"; import { SelectionOfComponentsData } from "./components/components/SelectionOfComponents";

const App: React.FC = () => { const [isAuthorized, setIsAuthorized] = useState( (IModelApp.authorizationClient?.hasSignedIn && IModelApp.authorizationClient?.isAuthorized) || false ); const [isLoggingIn, setIsLoggingIn] = useState(false); const [iModelId, setIModelId] = useState(process.env.IMJS_IMODEL_ID); const [contextId, setContextId] = useState(process.env.IMJS_CONTEXT_ID);

if (!process.env.IMJS_AUTH_CLIENT_CLIENT_ID) { throw new Error( "Please add a valid OIDC client id to the .env file and restart the application. See the README for more information." ); } if (!process.env.IMJS_AUTH_CLIENT_SCOPES) { throw new Error( "Please add valid scopes for your OIDC client to the .env file and restart the application. See the README for more information." ); } if (!process.env.IMJS_AUTH_CLIENT_REDIRECT_URI) { throw new Error( "Please add a valid redirect URI to the .env file and restart the application. See the README for more information." ); }

const authConfig: BrowserAuthorizationClientConfiguration = { scope: process.env.IMJS_AUTH_CLIENT_SCOPES ?? "", clientId: process.env.IMJS_AUTH_CLIENT_CLIENT_ID ?? "", redirectUri: process.env.IMJS_AUTH_CLIENT_REDIRECT_URI ?? "", postSignoutRedirectUri: process.env.IMJS_AUTH_CLIENT_LOGOUT_URI, responseType: "code", authority: "https://ims.bentley.com", };

useEffect(() => { if (isAuthorized) { const urlParams = new URLSearchParams(window.location.search); if (urlParams.has("contextId")) { setContextId(urlParams.get("contextId") as string); } else { if (!process.env.IMJS_CONTEXT_ID) { throw new Error( "Please add a valid context ID in the .env file and restart the application or add it to the contextId query parameter in the url and refresh the page. See the README for more information." ); } }

  if (urlParams.has("iModelId")) {
    setIModelId(urlParams.get("iModelId") as string);
  } else {
    if (!process.env.IMJS_IMODEL_ID) {
      throw new Error(
        "Please add a valid iModel ID in the .env file and restart the application or add it to the iModelId query parameter in the url and refresh the page. See the README for more information."
      );
    }
  }
}

}, [isAuthorized]);

useEffect(() => { if (contextId && iModelId && isAuthorized) { history.push(?contextId=${contextId}&iModelId=${iModelId}); } }, [contextId, iModelId, isAuthorized]);

useEffect(() => { if (isLoggingIn && isAuthorized) { setIsLoggingIn(false); } }, [isAuthorized, isLoggingIn]);

const onLoginClick = async () => { setIsLoggingIn(true); await IModelApp.authorizationClient?.signIn(); };

const onLogoutClick = async () => { setIsLoggingIn(false); await IModelApp.authorizationClient?.signOut(); setIsAuthorized(false); };

const onIModelConnected = (_imodel: IModelConnection) => { IModelApp.viewManager.onViewOpen.addOnce(async (vp: ScreenViewport) => { const viewStyle: DisplayStyleSettingsProps = { viewflags: { visEdges: false, shadows: true } }

  vp.overrideDisplayStyle(viewStyle);

  // IModelApp.viewManager.addDecorator(new SmartDeviceDecorator(vp));
  // console.log(await SmartDeviceAPI.getData())
})

} const onIModelAppInit = () => { setIsAuthorized(IModelApp.authorizationClient?.isAuthorized || false); IModelApp.authorizationClient?.onUserStateChanged.addListener(() => { setIsAuthorized( (IModelApp.authorizationClient?.hasSignedIn && IModelApp.authorizationClient?.isAuthorized) || false ); }); };

/** NOTE: This function will execute the "Fit View" tool after the iModel is loaded into the Viewer.

// This is to record the on-click events

SelectionOfComponentsData()

return (

{isLoggingIn ? ( "Logging in...." ) : ( )}

); };

export default App;

SelectionOfComponents.tsx

import { IModelApp,IModelConnection } from "@bentley/imodeljs-frontend"; import { ISelectionProvider, Presentation, PresentationManager, SelectionChangeEventArgs,PresentationManagerProps } from "@bentley/presentation-frontend"; import React, { useEffect } from "react"; import { SelectionSet } from "@bentley/imodeljs-frontend"; import {PresentationUnitSystem} from "@bentley/presentation-common" import { TileAdmin } from "@bentley/imodeljs-frontend";

export function SelectionOfComponentsData() {

React.useEffect(() => {

  Presentation.selection.selectionChange.addListener(_onSelectionChanged);

}

);

const _onSelectionChanged = async (evt: SelectionChangeEventArgs, selectionProvider: ISelectionProvider) => { const selection = selectionProvider.getSelection(evt.imodel, evt.level); console.log(selection)

};

// const getModelData = async (imodel:IModelConnection)=>{ // const query = // select UserLabel,ECInstanceId from Biscore.Geometricelement3d // // const results = imodel.query(query)

// const values = [];

// for await (const row of results){ // values.push(row); // // console.log(row); // }

// return values;

// }

}

grigasp commented 3 years ago

As far as I'm aware the Viewer does initialize the Presentation library. It's kind of hard to understand what's happening in your app, but my guess is that SelectionOfComponentsData gets called before the initialization is complete. I think the callback that tells you it's complete is onIModelConnected - please try calling your function from there.

Adding @aruniverse and @kckst8 into the conversation in case they have better suggestions.

kiranshetty07061999 commented 3 years ago

I tried calling it from onIModelConnected but that did not work.....I am getting this error

Unhandled Rejection (Error): Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app See https://fb.me/react-invalid-hook-call for tips about how to debug and fix this problem.
kckst8 commented 3 years ago

Hello, can you provide your onimodelconnected callback snippet?

kiranshetty07061999 commented 3 years ago

const onIModelConnected = (_imodel: IModelConnection) => { IModelApp.viewManager.onViewOpen.addOnce(async (vp: ScreenViewport) => { const viewStyle: DisplayStyleSettingsProps = { viewflags: { visEdges: false, shadows: true } }

i have called this in the Viewer

onIModelConnected = {onIModelConnected}

kckst8 commented 3 years ago

Have you tried adding your presentation listener in that function (Presentation. Presentation.selection.selectionChange.addListener(_onSelectionChanged)?

grigasp commented 3 years ago

I missed the part that SelectionOfComponentsData uses a hook. Try removing the hook and simply changing it to this:

export function SelectionOfComponentsData() {
  Presentation.selection.selectionChange.addListener(_onSelectionChanged);

  const _onSelectionChanged = async (evt: SelectionChangeEventArgs, selectionProvider: ISelectionProvider) => {
    const selection = selectionProvider.getSelection(evt.imodel, evt.level);
    console.log(selection);
  }
}
kiranshetty07061999 commented 3 years ago

I tried adding this code

import { RequestPriority } from "@bentley/presentation-common"; import { Presentation, PresentationManagerMode } from "@bentley/presentation-backend"; import rpcs from "../common/Rpcs"; // initialize presentation-backend Presentation.initialize({ rulesetDirectories: [path.join("assets", "presentation_rules")], localeDirectories: [path.join("assets", "locales")], mode: PresentationManagerMode.ReadWrite, taskAllocationsMap: {

}, useMmap: true, updatesPollInterval: 20, });

but i am not sure how to include rpcs file

kiranshetty07061999 commented 3 years ago

@grigasp It worked...thanks a lot