Autodesk Forge: Viewer Extension cant use .getExternalIdMapping() - javascript

class IBSProgressExtension extends Autodesk.Viewing.Extension{
constructor(viewer, options) {
super(viewer, options);
}
load() {
//For proof of concept project, I will simply store the externalIds here in a variable.
const allExternalIds = [
'8a00f4c7-0709-4749-88b6-abb0ddccf965-0006879a',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-000688ee',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068961',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068963',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a78',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0d',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0f',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a11',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a13',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c2f',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c31',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c33',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b2e',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b30',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b32',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b34',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3e',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b36',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b38',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3a',
'8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3c'
];
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
function onSuccessMapping(data) {
const resArray = [];
allExternalIds.forEach(externalId => {
if (data[externalId]) resArray.push(data[externalId], externalId);
});
console.log(resArray);
};
console.log('IBSProgressExtension is loaded.');
return true;
}
};
Autodesk.Viewing.theExtensionManager.registerExtension("IBSProgressExtension", IBSProgressExtension);
Please have a look at my extension and please help me figure out why is this happening.
Every time i run it, the devtools logs: ViewerExtension.js:31 Uncaught TypeError: Cannot read properties of undefined (reading 'getExternalIdMapping').

The extensions get loaded before the model so the getExternalIdMapping() method does not have the model properties yet. To handle this scenario, we usually recommend using the viewer events such as Autodesk.Viewing.GEOMETRY_LOADED_EVENT to “catch” the moment when the model is available. It’s better to wait for the event. This will be fired when the model/drawing finishes loading.
Instead of:
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
Try this:
this.viewer.addEventListener(Autodesk.Viewing.GEOMETRY_LOADED_EVENT, (x) => {
this.viewer.model.getExternalIdMapping(data => onSuccessMapping(data));
});

Please test this and see if it's helpful. I tried to incorporate items from your comments to help you structure it out.
class IBSProgressExtension extends Autodesk.Viewing.Extension {
constructor(viewer, options) {
super(viewer, options);
this._externalIds = null;
//Eventually will want to pass in your external IDs to this function, I assume:
//this._externalIds = options.externalIds
this._doStuff = () => {
this.startDoingStuff();
};
}
load() {
console.log("loading extension");
//For now, hard coded like your example.
this._externalIds = [
"8a00f4c7-0709-4749-88b6-abb0ddccf965-0006879a",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-000688ee",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068961",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068963",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a78",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0d",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a0f",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a11",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068a13",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c2f",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c31",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068c33",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b2e",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b30",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b32",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b34",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3e",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b36",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b38",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3a",
"8a00f4c7-0709-4749-88b6-abb0ddccf965-00068b3c",
];
//Not sure if this is truly the right event, but it worked when I tested on mine.
this.viewer.addEventListener(Autodesk.Viewing.MODEL_LAYERS_LOADED_EVENT, this._doStuff);
}
startDoingStuff() {
console.log("startDoingStuff executing");
this.getDbIds(this._externalIds).then((CombinedArray) => {
this.setCustomColors(CombinedArray);
});
}
setCustomColors(arrayOfIDs) {
console.log("setCustomColors executing");
var somecolor = "#7D5B51";
var threecolor = new THREE.Color(somecolor);
var vectcolor = new THREE.Vector4(threecolor.r, threecolor.g, threecolor.b, 1);
arrayOfIDs.forEach((e) => {
this.viewer.setThemingColor(e[0], vectcolor, this.viewer.getVisibleModels()[0]);
});
}
getDbIds(externalIds) {
console.log("getDbIds executing");
return new Promise((resolve) => {
this.viewer.model.getExternalIdMapping((d) => {
//console.log("getDbIdFromExternalId Executed");
let responseArr = [];
externalIds.forEach((externalId) => {
if (d[externalId]) responseArr.push([d[externalId], externalId]);
});
console.log("resolving", responseArr);
resolve(responseArr);
});
});
}
}
Autodesk.Viewing.theExtensionManager.registerExtension("IBSProgressExtension", IBSProgressExtension);

Regarding this, I was trying to achieve 3 things at this stage.
Get the externalIds from Mongodb.
Compare the externalIds with the ones gotten from getExternalIdMapping().
Get DbIds of those that matched.
Solved these by realising 2 and 3 can be put inside a.then() after .loadDocumentNode().

Related

RxJS indexOfQuizId undefined in console

I've started refactoring my code to work with Angular Observables and I'm using the Observable 'of' for the quizzes$ array, but I'm stuck at getting indexOfQuizId working, specifically with findIndex. I am getting an undefined value for this.indexOfQuizId in the console, not sure what I'm doing wrong... Please could you see my code below (in getIndexOfQuizId()) and help to get it to work. Thank you!
In quiz.ts:
export const getQuizzes$: Observable<Quiz[]> = of([quiz data inside array]);
In quiz.service.ts:
export class QuizService {
quizzes$: Observable<Quiz[]>;
...
constructor(...) {
this.quizzes$ = getQuizzes$;
...
}
getQuizzes(): Observable<Quiz[]> {
return this.quizzes$;
}
getIndexOfQuizId() {
const index = this.getQuizzes().pipe(map(quizzes => {
this.indexOfQuizId = quizzes.findIndex((elem) => elem.quizId === this.quizId);
})).subscribe(x => {
console.log(x);
console.log('IOQID: ', this.indexOfQuizId);
});
}
In quiz.component.html, I'm using this.indexOfQuizId to access the quizzes$ array object like this:
this.totalQuestions = this.quizzes$[this.quizService.indexOfQuizId].questions.length;
You have an undefined for this line console.log('IOQID: ', this.indexOfQuizId); and it's quite right.
As you may know, the subscribe is asynchronous, that means that the next line (console.log('IOQID: ', this.indexOfQuizId);) is called before you set any value into this.indexOfQuizId since the map will be called eventually.
Try to move the console.log into the subscribe like this:
getIndexOfQuizId() {
const index = this.getQuizzes().pipe(map(quizzes => {
this.indexOfQuizId = quizzes.findIndex(function(elem, i, obs) { return elem => elem.quizId === this.quizId; });
})).subscribe(x => {
console.log(x);
console.log('IOQID: ', this.indexOfQuizId);
});
}

unable to change image source in DOM javascript

I’m Rahul and I’m new to coding. I have a query related to DOM event. Please look at the following code snippet -
let door1 = document.getElementById('one');
door1.src = "closed_door.svg";
const isClicked = (door) => {
if(door.src === "closed_door.svg") {
return true;
}
else {
return false;
}
};
door1.onclick = () => {
if(isClicked(door1)) {
door1.src = "beach.svg";}
};
To give you brief, one is an id for an element. Without isClicked, I am able to successfully change the src from closed door to beach on clicking. But when I introduce isClick, it doesn’t change. Can someone please tell me what I’m missing. I’ll be very thankful
Note - I'm building game similar to this - https://s3.amazonaws.com/codecademy-content/projects/chore-door/chore-door-final/index.html They are using the same process as mine. So please suggest a solution that tells me about the error I'm making here rather than an alternative to the problem
Regards
Rahul
As reported here:
the src reflected property will be the resolved URL — that is, the absolute URL that that turns into. So if that were on the page http://www.example.com, document.getElementById("foo").src would give you "http://www.example.com/images/example.png".
so to get the real src attribute you should use .getAttribute('src') like so:
const isClicked = (door) => {
if(door.getAttribute('src') === "closed_door.svg") {
return true;
}
else {
return false;
}
};
Ans also BTW, you can just shortcut it to:
const isClicked = (door) => door.getAttribute('src') === "closed_door.svg";
Replace your code with this..
let door1 = document.getElementById('one');
door1.src = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg";
const isClicked = (door1) => {
if(door1.src === "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/closed_door.svg") {
return true;
}
else {
return false;
}
};
door1.onclick = () => {
if(isClicked(door1)) {
door1.src = "https://s3.amazonaws.com/codecademy-content/projects/chore-door/images/beach.svg";}
};

How to know when real time update ends - Cloud Firestore ionic 4 with angular

I'm using cloud firestore for my DB, having no problems with read and writes. My issue is that i don't understand how to know when real time update has ended!
I'm using real time update as described in official cloud firestore documentation. It returns a function instead an observable. Now i'm not sure how to use it correctly.
I need to execute some code after data is loaded, but i have no subscribe((data) => {...}) to put it there!!
How to do it?
If i show lack of knowledge, please guide me to some documentation.
Thanks
This code is working fine and i'm using it directly on html like ListService.places$ to access data array.
public places$: BehaviorSubject<Array<Place>> = new BehaviorSubject<Array<Place>>([]);
private unsubscribe: Function;
public list(city: string, country: string) {
return this.unsubscribe = this.firestore.firestore.collection('places')
.where("location.country", "==", country)
.where("location.city", "==", city)
.orderBy("startDate", "desc")
.onSnapshot(querySnapshot => {
const list: Place[] = [];
if(!querySnapshot.docs.length) {
this.places$.next(list);
} else {
querySnapshot.docs.forEach(doc => {
let places = new Place();
place = doc.data() as Place;
places.push(place);
if(list.length === querySnapshot.docs.length) {
this.places$.next(list);
}
});
}
});
}
You need to subscribe to this.places$
this.places$.subscribe((data) => {
console.log(data);
});
What the real time function returns does not metter, because the real time function adds the output to the BehaviorSubject.
See here
let places = new Place();
place = doc.data() as Place;
places.push(place);
if(list.length === querySnapshot.docs.length) {
this.places$.next(list);
}
That means if you want to do something with the data you just need to subscribe to places$.
Also i think you have a small typo there, you never pushed values to the list array.
It should be something like:
...
.onSnapshot(querySnapshot => {
const list: Place[] = [];
if(!querySnapshot.docs.length) {
this.places$.next(list);
} else {
querySnapshot.docs.forEach(doc => {
let place = new Place();
place = doc.data() as Place;
list.push(place);
if(list.length === querySnapshot.docs.length) {
this.places$.next(list);
}
});
}
});

Javascript Observable performance issue

Current Working Code
I have the following rxjs/Observable:
findMessages(chatItem: any): Observable<any[]> {
return Observable.create((observer) => {
let processing: boolean = false;
this.firebaseDataService.findMessages(chatItem).forEach(firebaseItems => {
if (!processing) {
processing = true;
this.localDataService.findMessages(chatItem).then((localItems: any[]) => {
let mergedItems: any[] = this.arrayUnique(firebaseItems.concat(localItems), false);
mergedItems.sort((a, b) => {
return parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp);
});
if (this.me && mergedItems && mergedItems[0] && this.me.uid === mergedItems[0].memberId2) {
this.updateChatWithMessage(chatItem, mergedItems[0], false);
}
observer.next(mergedItems);
processing = false;
});
}
});
});
}
and
this.firelist = this.dataService.findMessages(this.chatItem);
this.firelist.subscribe(items => {
...
});
As you can see, it returns a list of firebaseItems and localItems, which are merged to mergedItems. This works perfectly.
Performance Enhancement
However, I am trying to increase the performance that the items load. So figure, I would like to first load the localItems, and then add to the list with the firebaseItems.
So I try add the following function:
findLocalMessages(chatItem: any): Observable<any[]> {
return Observable.create((observer) => {
this.localDataService.findMessages(chatItem).then((localItems: any[]) => {
localItems.sort((a, b) => {
return parseFloat(a.negativtimestamp) - parseFloat(b.negativtimestamp);
});
observer.next(localItems);
});
});
}
and call it as follows:
this.firelist = this.dataService.findLocalMessages(this.chatItem);
this.firelist = this.dataService.findMessages(this.chatItem);
this.firelist.subscribe(items => {
...
});
Problem
This has now introduced a bug, that there are now 2 Observables and the results are not as expected. The sort order is incorrect, and some of the items are not being added to the this.firelist for some reason.
Question
Whats the best way to handle this?
I was thinking if it's possible to make the findLocalMessages Observable only get fired once, and then it never works again, as the findMessages Observable will maintain the list. Is this possible? I have been looking at the Observable api, and can't seem to figure out how to do that.
Any help appreciated.
With the risk of oversimplifying the problem statement, you have two streams of data that you want to merge and sort in an efficient manner.
The separation you have made is a step in the right direction.
The reason why you are not getting all the messages is that you are overriding the first observable with the second.Have a look at the following example and see what happens if you try and assign the second observable to move instead of move2.
let move = Observable.fromEvent(document.getElementById("1"), 'mousemove');
let move2 = Observable.fromEvent(document.getElementById("2"), 'mousemove');
move
.subscribe((event:any) => {
if (event) {
console.log(event.path[0].id)
}
});
move2
.subscribe((event:any) => {
if (event) {
console.log(event.path[0].id)
}
});
<h1>
<div id="1">
aaaaaaaaaaaaaaaaaaaaaaaaa
</div>
<div id="2">
bbbbbbbbbbbbbbbbbbbbbbbbb
</div>
</h1>
In order to merge the two streams together properly you need to use the merge operator as shown below:
let move = Observable.fromEvent(document.getElementById("1"), 'mousemove');
let move2 = Observable.fromEvent(document.getElementById("2"), 'mousemove');
move.merge(move2)
.subscribe((event:any) => {
if (event) {
console.log(event.path[0].id)
}
});
Now all you need to do is sort them. I would advice that you do the sort only after the merge because otherwise, you will end up with two streams that are sorted locally, not globally.

Waiting for multiple async operations in Nightwatch.js

I am attempting to test multiple sites for section headers being in the correct order. Of course everything is asynchronous in Nightwatch, including getting text from an element. The following code leads to the timeout never being called.
client.url(`www.oneofmyrealestatesites.com`);
client.waitForElementPresent("body", 5000);
var _ = require("underscore");
// This is the order I expect things to be in
var expected = ["Homes For Sale", "New Homes", "Apartments & Rentals"];
client.elements("css selector", ".listings .module-title .label", function (data) {
var listings = [];
data.value.forEach(function (element) {
client.elementIdText(element.ELEMENT, function (result) {
listings.push(result.value);
})
})
setTimeout(function () {
// Some of the sites have extra sections
var diff = _.intersection(listings, expected);
client.assert.ok(listings == diff);
}, 5000);
});
It would appear that no matter how much delay I give, listings is ALWAYS empty. If I console.log listings as it's being pushed to, it is getting populated, so that's not the issue. client.pause is always ignored as well.
Is there a way to make sure that listings is populated before asserting the diff?
I'm using async library for such cases https://github.com/caolan/async
Docs: https://github.com/caolan/async/blob/v1.5.2/README.md
var async = require("async");
/*use each, eachSeries or eachLimit - check docs for differences */
async.eachSeries(data.value, function (element, cb) {
client.elementIdText(element.ELEMENT, function (result) {
listings.push(result.value);
// this job is done
cb();
});
}, function() {
// Some of the sites have extra sections
var diff = _.intersection(listings, expected);
client.assert.ok(listings == diff);
});
setTimeout can only be called from .execute or .executeAsync because its actual javascript. The function below was only working until I used .executeAsync
Hope this works for you.
Cheers, Rody
LoopQuestionsLogSymptom: function() {
this.waitForElementVisible('.next-button', constants.timeout.medium, false);
this.api.executeAsync(function() {
let checkQuestion = function() {
// GET THE ELEMENTS
let nextButton = document.querySelectorAll('.next-button');
let answers = document.getElementsByClassName('flex-row');
let blueButton = document.querySelector('.blue-inverse-button');
let doneButton = document.querySelector('#doneButton');
let monitor = document.querySelector('.monitor');
//CHECK THE TYPES OF QUESTIONS AND CLICK THE RIGHT BUTTONS
if (!blueButton) {
answers[0].click();
nextButton[0].click()
} else if(blueButton){
blueButton.click();
}
setTimeout(() => {
if(!doneButton) {
console.log('Answering another question!');
checkQuestion();
}
if(doneButton){
doneButton.click();
}
else if(monitor) {
console.log("Exiting?")
.assert(monitor);
return this;
}
}, 2000);
};
// Initiating the check question function
return checkQuestion();
},[], function(){
console.log('Done?')
});
this.waitForElementVisible('.monitor', constants.timeout.medium);
this.assert.elementPresent('.monitor');
this.assert.urlEquals('https://member-portal.env-dev4.vivantehealth.org/progress');
return this;
},

Categories

Resources