Vue3: Unable to access proxy's target data - javascript

This is my first question so I'll try to explain the problem as much as I can.
I'm working on a Vue3 project, where I have a component that receives props, these props are treated as proxys in Vue (reactivity purposes).
The problem comes when reading the data. The proxy's target seems to have data, but when console.log() the object.property, shows undefined:
console.log(this.slideResults)
console.log(JSON.parse(JSON.stringify(this.slideResults)))
My component:
export default defineComponent({
props: {
takenImage: HTMLImageElement,
slideResults: Object, // slideResults = {[opencvResults], [possibleDuplicatedImages]}
},
components: { Swiper, Slide, SwiperSlide },
computed: {
getImages() {
// console.log the prop -> target = Object{canvasResults: canvas, possibleDuplicatedImages: }
console.log(this.slideResults);
const slideResults = JSON.parse(JSON.stringify(this.slideResults));
console.log(slideResults);
console.log(slideResults.canvasResults);
console.log(slideResults.possibleDuplicatedImages);
// To destructure props and don't lose reactivity we need to convert them into ref
// const { slideResults } = toRaw(this.slideResults);
// console.log(slideResults);
// const { canvasResults, possibleDuplicatedImages } = toRaw(
// this.slideResults
// );
// console.log(canvasResults[0]);
// console.log(this.takenImage);
// // In order to pass to a slide the images as: Array<Object> where [{imageFile, canvas}]
// /**
// * #type {Array<{ image: HTMLCanvasElement[], opencvResult: File[] }>}
// */
const images = [];
// for (let i = 0; i < canvasResults.length; i++) {
// images.push({
// image: possibleDuplicatedImages[i],
// opencvResult: canvasResults[i],
// });
// }
// console.log(images);
return images;
},
},
});
I have also tried with this, where the logs return the same as above:
export default defineComponent({
props: {
takenImage: HTMLImageElement,
slideResults: Object, // slideResults = {[opencvResults], [possibleDuplicatedImages]}
},
components: { Swiper, Slide, SwiperSlide },
setup(props) {
/**
* Returns the images to use in the slides
*/
const getImages = () => {
// To destructure props and don't lose reactivity we need to convert them into ref
const { slideResults } = toRefs(props);
const { canvasResults, possibleDuplicatedImages } = toRaw(
slideResults.value
);
console.log(canvasResults);
console.log(possibleDuplicatedImages);
console.log(props.takenImage);
// In order to pass to a slide the images as: Array<Object> where [{imageFile, canvas}]
/**
* #type {Array<{ image: HTMLCanvasElement[], opencvResult: File[] }>}
*/
const images = [];
for (let i = 0; i < canvasResults.length; i++) {
images.push({
image: possibleDuplicatedImages[i],
opencvResult: canvasResults[i],
});
}
console.log(images);
return images;
};
return {
modules: [Autoplay, Keyboard, Pagination, Zoom, Navigation],
getImages,
};
},
});

Related

I can't get my data from my document with firebase

I'm creating a single page application with javascript by using the firebase firestore as database.
I've managed to get all my documents listed where I call for all of them. Each document has an href to the detail page. But on the detailpage, it looks like I don't have any data from my document.
I want to call the title from the document to show as an h1 but noting renders and I don't have any errors in my console..
Anyone who can help me?
My code:
This is to get all the documents (who are events)
// Get events
import firebase from 'firebase/app';
import 'firebase/firestore';
const Events = {
getAll: async () => {
// get firestore
const db = firebase.firestore();
// define query
const query = db.collection('events');
// query snapshot
const querySnapshot = await query.get();
// loop over all documents
return querySnapshot.docs.map((doc) => (
{
...doc.data(),
id: doc.id,
}
));
},
// get the data from a detailpage by the ID
getById: async (id) => {
const db = firebase.firestore();
const event = await (await (db.collection('events').doc(id).get())).data();
return event;
},
};
export default Events;
My component to render all documents as a list
import Component from '../lib/Component';
import Elements from '../lib/Elements';
import Router from '../Router';
import Events from '../lib/Events';
class EventsComponent extends Component {
constructor() {
super({
name: 'events',
model: {
events: [],
},
routerPath: '/events',
});
this.eventsLoaded = false;
}
// Get the events one by one, make them an href to their detail page and show the name of the
event
loadEvents() {
if (!this.eventsLoaded) {
Events.getAll().then((data) => {
this.model.events = data.map((event) => ({
href: `${Router.getRouter().link('/event')}/${event.id}`,
textContent: event.title,
}));
});
this.eventsLoaded = true;
}
}
render() {
const { events } = this.model;
// create home container
const eventsContainer = document.createElement('div');
// Load events
this.loadEvents();
// Check if there are any events
if (events.length === 0) {
eventsContainer.innerHTML = 'There are no events planned at the moment';
} else {
eventsContainer.appendChild(
Elements.createList({
items: this.model.events,
}),
);
}
return eventsContainer;
}
}
export default EventsComponent;
My detail page
// Event Component
import Component from '../lib/Component';
import Elements from '../lib/Elements';
import Events from '../lib/Events';
class EventComponent extends Component {
constructor() {
super({
name: 'event',
model: {
event: [],
},
routerPath: '/event/:id',
});
this.eventLoaded = false;
}
// Set the model loading to true when the id page is founded
loadEvent(id) {
if (!this.eventLoaded) {
this.eventLoaded = true;
Events.getById(id).then((data) => {
this.model.event = data;
});
}
}
render() {
const { event } = this.model;
// create event overview container
const eventContainer = document.createElement('div');
// Check for existing events and return the events.
// Create an h1 with the name of the event as title
if (!event) {
this.loadEvent(this.props.id);
} else {
eventContainer.appendChild(
Elements.createHeader({
textContent: event.title,
}),
);
console.log(this.model.event);
}
return eventContainer;
}
}
export default EventComponent;
You have model set as an array insted of an object in you detail page.
constructor() {
super({
name: 'event',
model: {
event: [],
},
routerPath: '/event/:id',
});
this.eventLoaded = false;
}
When you try to access your event you are trying to get .title from an array insted of an object.
Elements.createHeader({
textContent: event.title,
}),
I would map the event field by field { "field" : 0, "field2": ""} but you may find a way to make it less verbose

How to write JavaScript code that allows for defaults to be overrided

I would like to use this text-highlighting library in my Vue project. Here's an example from their website of how it can be used:
import TextHighlighter from '#perlego/text-highlighter';
import { isDuplicate } from './utils';
import highlightsApi from './services/highlights-api';
class ArticleView {
constructor(data) {
this.data = data;
const pageElement = document.getElementById("article");
this.highlighter = new TextHighlighter(
pageElement,
{
version: "independencia",
onBeforeHighlight: this.onBeforeHighlight,
onAfterHighlight: this.onAfterHighlight,
preprocessDescriptors: this.preprocessDescriptors,
onRemoveHighlight: this.onRemoveHighlight
});
}
onBeforeHighlight = (range) => {
return !isDuplicate(range)
}
onRemoveHighlight = (highlightElement) => {
const proceed = window.confirm("Are you sure you want to remove this highlight?");
return proceed;
}
preprocessDescriptors = (range, descriptors, timestamp) => {
// Add an ID to the class list to identify each highlight
// (A highlight can be represented by a group of elements in the DOM).
const uniqueId = `hlt-${Math.random()
.toString(36)
.substring(2, 15) +
Math.random()
.toString(36)
.substring(2, 15)}`;
const descriptorsWithIds = descriptors.map(descriptor => {
const [wrapper, ...rest] = descriptor;
return [
wrapper.replace(
'class="highlighted"',
`class="highlighted ${uniqueId}"`
),
...rest
];
});
return { descriptors: descriptorsWithIds, meta: { id: uniqueId } };
}
onAfterHighlight = (range, descriptors, timestamp, meta) => {
highlightsApi.saveBatch(meta.id, descriptorsWithIds)
.then((result) => {
// Do something with the highlights that have been saved.
})
.catch((err) => console.error(err));
}
render = () => {
// Code that takes the data for the article and adds it to the DOM
// based on a html template here.
}
}
Using the above example, I would like to setup the highlighter (similar to the above code, but in a different file, for example ./utils/highlighter.js) with all the default options I want (onBeforeHighlight, onRemoveHighlight, etc.), and then be able to import it from there and override the options for which I don't want to use the defaults, so it looks something like this in the importing file:
import highlighter from "../utils/highlighter.js";
const overridingOptions = {
onAfterHighlight: (range, descriptors, timestamp, meta) => {
console.log(range, descriptors, timestamp, meta);
}
};
const target = document.getElementsByClassName("testme")[0];
highlighter(target, overridingOptions);
For some reason, I am not able to understand how to modify the ArticleView example to fit my needs, so I think I need to see this done once. How should the code in ./utils/highlighter.js look to make this possible?

Call a class method from a another class in JavaScript?

I am doing a task where I need to wire up a search field to a simple JS application that displays a few items and the user can search through and filter them.
There are three classes - App, ProductsPanel and Search. Both Search and ProductsPanel are being initialised inside the App class.
The ProductsPanel class holds an array with 10 products.
I want to call a method of ProductsPanel from inside Search that filters through the products. How can I do that?
I've tried using this.productsPanel = new productsPanel() inside the constructor of the first class, but that brings up a new instance which doesn't have the array of all of the products.
Here's the App class:
class App {
constructor() {
this.modules = {
search: {
type: Search,
instance: null
},
filter: {
type: Filter,
instance: null
},
productsPanel: {
type: ProductsPanel,
instance: null
},
shoppingCart: {
type: ShoppingCart,
instance: null
}
};
}
init() {
const placeholders = document.querySelectorAll("#root [data-module]");
for (let i = 0; i < placeholders.length; i++) {
const root = placeholders[i];
const id = root.dataset.module;
const module = this.modules[id];
if (module.instance) {
throw new Error(`module ${id} has already been started`);
}
module.instance = new module.type(root);
module.instance.init();
// console.info(`${id} is running...`);
}
}
}
app = new App();
app.init();
And here are the Search:
export default class Search {
constructor(root) {
this.input = root.querySelector("#search-input");
}
// addEventListener is an anonymous function that encapsulates code that sends paramaters to handleSearch() which actually handles the event
init() {
this.input.addEventListener("input", () => {
this.handleSearch();
});
}
handleSearch() {
const query = this.input.value;
app.modules.productsPanel.instance.performSearch(query);
}
}
And ProductsPanel classes:
export default class ProductsPanel {
constructor(root) {
this.view = new ProductsPanelView(root, this);
this.products = [];
}
init() {
this.products = new ProductsService().products;
this.products.forEach(x => this.view.addProduct(x));
}
performSearch(query) {
query = query.toLowerCase();
this.products.forEach(p => {
if (query === p.name) {
this.view.showProduct(p.id);
} else {
this.view.hideProduct(p.id);
}
});
}
addToCart(id) {
const product = this.products.filter(p => p.id === id)[0];
if (product) {
app.modules.shoppingCart.instance.addProduct(product);
}
}
}
I want to call ProductsPanel's performSearch method but on the instance created by the App class. I have no clue on how I can do that.
Try below custom event handler class
class CustomEventEmitter {
constructor() {
this.eventsObj = {};
}
emit(eName, data) {
const event = this.eventsObj[eName];
if( event ) {
event.forEach(fn => {
fn.call(null, data);
});
}
}
subscribe(eName, fn) {
if(!this.eventsObj[eName]) {
this.eventsObj[eName] = [];
}
this.eventsObj[eName].push(fn);
return () => {
this.eventsObj[eName] = this.events[eName].filter(eventFn => fn !== eventFn);
}
}
}
How to use?
create the object of CustomEventEmitter class
let eventEmitter = new CustomEventEmitter()
Subscribe an event
emitter.subscribe('event: do-action', data => {
console.log(data.message);
});
call the event
emitter.emit('event: do-action',{message: 'My Custom Event handling'});
Hope this helps!

VTK.js VR not display/showing an hand controller in Room

I try to use VTK VR, but When I test it, I cant see controller in room, I can get action from controller like press or somthing, but without its seen for user in VR mode, how I can fix it?
Online Demo From Here.
import 'vtk.js/Sources/favicon';
import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkCalculator from 'vtk.js/Sources/Filters/General/Calculator';
import vtkConeSource from 'vtk.js/Sources/Filters/Sources/ConeSource';
import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import { AttributeTypes } from 'vtk.js/Sources/Common/DataModel/DataSetAttributes/Constants';
import { FieldDataTypes } from 'vtk.js/Sources/Common/DataModel/DataSet/Constants';
import controlPanel from './controller.html';
// ----------------------------------------------------------------------------
// Standard rendering code setup
// ----------------------------------------------------------------------------
const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance({
background: [0, 0, 0],
});
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();
// ----------------------------------------------------------------------------
// Example code
// ----------------------------------------------------------------------------
// create a filter on the fly, sort of cool, this is a random scalars
// filter we create inline, for a simple cone you would not need
// this
// ----------------------------------------------------------------------------
const coneSource = vtkConeSource.newInstance({ height: 100.0, radius: 50.0 });
// const coneSource = vtkConeSource.newInstance({ height: 1.0, radius: 0.5 });
const filter = vtkCalculator.newInstance();
filter.setInputConnection(coneSource.getOutputPort());
// filter.setFormulaSimple(FieldDataTypes.CELL, [], 'random', () => Math.random());
filter.setFormula({
getArrays: (inputDataSets) => ({
input: [],
output: [
{
location: FieldDataTypes.CELL,
name: 'Random',
dataType: 'Float32Array',
attribute: AttributeTypes.SCALARS,
},
],
}),
evaluate: (arraysIn, arraysOut) => {
const [scalars] = arraysOut.map((d) => d.getData());
for (let i = 0; i < scalars.length; i++) {
scalars[i] = Math.random();
}
},
});
const mapper = vtkMapper.newInstance();
mapper.setInputConnection(filter.getOutputPort());
const actor = vtkActor.newInstance();
actor.setMapper(mapper);
actor.setPosition(20.0, 0.0, 0.0);
renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();
// -----------------------------------------------------------
// UI control handling
// -----------------------------------------------------------
fullScreenRenderer.addController(controlPanel);
const representationSelector = document.querySelector('.representations');
const resolutionChange = document.querySelector('.resolution');
const vrbutton = document.querySelector('.vrbutton');
representationSelector.addEventListener('change', (e) => {
const newRepValue = Number(e.target.value);
actor.getProperty().setRepresentation(newRepValue);
renderWindow.render();
});
resolutionChange.addEventListener('input', (e) => {
const resolution = Number(e.target.value);
coneSource.setResolution(resolution);
renderWindow.render();
});
vrbutton.addEventListener('click', (e) => {
if (vrbutton.textContent === 'Send To VR') {
fullScreenRenderer.getOpenGLRenderWindow().startVR();
vrbutton.textContent = 'Return From VR';
} else {
fullScreenRenderer.getOpenGLRenderWindow().stopVR();
vrbutton.textContent = 'Send To VR';
}
});
// -----------------------------------------------------------
// Make some variables global so that you can inspect and
// modify objects in your browser's developer console:
// -----------------------------------------------------------
global.source = coneSource;
global.mapper = mapper;
global.actor = actor;
global.renderer = renderer;
global.renderWindow = renderWindow;
Note: Tested on Latest Version of Chrome & Firefox (64 bit). Controller Type is HTC Vive.
Update 1:
We found this option not development, so that I share updated link now Github Link

NuxtServerError: Cannot find module 'undefined'

I'm trying to dynamically upload images into a vuetify carousel component from a folder I've added to the project path called 'Main'.
My component looks like:
<template>
<v-carousel>
<v-carousel-item v-for="(item,i) in items" :key="i" :src="item.src"></v-carousel-item>
</v-carousel>
</template>
<script>
function getImagePaths() {
// var images = require.context('../../main/img/', false, /\.png$/)
var images = require.context("../../main/", false, /\.png$/);
// var images = require.context('/main/', false, /\.png$/)
console.log("images", images);
return images;
}
export default {
methods: {
imgUrl: getImagePaths()
}
};
I'm getting the:
NuxtServerError: Cannot find module 'undefined'
(screenshot above) How can I fix this?
EDIT: if I change the Script tag to:
<script>
// function getImagePaths() {
// // Load locally as a function.
// const fs = require("fs-extra");
// var requireContext = require("require-context");
// // var images = require.context('../../main/img/', false, /\.png$/)
// var images = require.context("../../main/", false, /\.png$/);
// // var images = require.context('/main/', false, /\.png$/)
// console.log("images", images);
// return images;
// }
// export default {
// methods: {
// imgUrl: getImagePaths()
// }
// };
export default {
data () {
return {
items: [
{
src: 'https://cdn.vuetifyjs.com/images/carousel/squirrel.jpg'
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/sky.jpg'
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/bird.jpg'
},
{
src: 'https://cdn.vuetifyjs.com/images/carousel/planet.jpg'
}
]
}
}
}
</script>
It works as expected.

Categories