0
votes

Essentially I have a modal window in aframe that I am trying to add a close button to via javascript but I haven't been able to figure it out.

Link to the project below:

https://andrewmc1994.github.io/Image-Link-Test/

If you highlight the compass icon you will see what I mean.

This is for a university project, i've looked at various methods online but none of them seem to work so that's why I have come here.

        <a-entity ui-modal="triggerElement:#selection;" visible="false">

         <a-image src="#submenu" scale="3.5 3.5 0" position="0 -0.25 2" src-fit></a-image>

            <a-image position="-1 -0.25 2.1" class="clickable" src="#tqicon" scale="0.7 0.7 0" link="href:location1.html; on: click; visualAspectEnabled: false" src-fit></a-image>

             <a-image position="0 -0.25 2.1" class="clickable" src="#acicon" scale="0.7 0.7 0" link="href:location3.html; on: click; visualAspectEnabled: false" src-fit></a-image>

             <a-image position="1 -0.25 2.1" class="clickable" src="#bchicon" scale="0.7 0.7 0" link="href:location2.html; on: click; visualAspectEnabled: false" src-fit></a-image>

            <a-image position="1.4 0 2.1" class="clickable" src="#close" scale="0.1 0.1 0" id="close" src-fit></a-image>

        </a-entity>

/******/ (function(modules) { // webpackBootstrap
/******/    // The module cache
/******/    var installedModules = {};

/******/    // The require function
/******/    function __webpack_require__(moduleId) {

/******/        // Check if module is in cache
/******/        if(installedModules[moduleId])
/******/            return installedModules[moduleId].exports;

/******/        // Create a new module (and put it into the cache)
/******/        var module = installedModules[moduleId] = {
/******/            exports: {},
/******/            id: moduleId,
/******/            loaded: false
/******/        };

/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/        // Flag the module as loaded
/******/        module.loaded = true;

/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }


/******/    // expose the modules object (__webpack_modules__)
/******/    __webpack_require__.m = modules;

/******/    // expose the module cache
/******/    __webpack_require__.c = installedModules;

/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "";

/******/    // Load entry module and return exports
/******/    return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports) {

    /**
     * UI modal component for A-Frame.
     */

    if (typeof AFRAME === 'undefined') {
      throw new Error('Component attempted to register before AFRAME was available.');
    }

    AFRAME.registerComponent('ui-modal', {

        schema: {
            trigger: {
                default: 'click'
            },
            triggerElement: {
              default: '',
            },
            zpos: {
                default: -4
            }
        },

        init: function() { 

            document.querySelector(this.data.triggerElement).addEventListener(this.data.trigger, this.eventHandler.bind(this));

            this.cameraEl = document.querySelector('a-entity[camera]');

            this.yaxis = new THREE.Vector3(0, 0, 0);
            this.zaxis = new THREE.Vector3(0, 0, 0);

            this.pivot = new THREE.Object3D();
            this.el.object3D.position.set(0, this.cameraEl.object3D.getWorldPosition().y, this.data.zpos);

            this.el.sceneEl.object3D.add(this.pivot);
            this.pivot.add(this.el.object3D);

        },


        eventHandler: function(evt) {

            if (this.el.getAttribute('visible') === false) {

                var direction = this.zaxis.clone();
                direction.applyQuaternion(this.cameraEl.object3D.quaternion);
                var ycomponent = this.yaxis.clone().multiplyScalar(direction.dot(this.yaxis));
                direction.sub(ycomponent);
                direction.normalize();

                this.pivot.quaternion.setFromUnitVectors(this.zaxis, direction);
                this.pivot.position.copy(this.cameraEl.object3D.getWorldPosition());

                this.el.setAttribute('visible', true);

            } else if (this.el.getAttribute('visible') === true) {

                this.el.setAttribute('visible', false);
            }

        },

        update: function (oldData) {},

        remove: function() {}

    });




/***/ }
/******/ ]);

So the expected result is for the user to open the modal window and then have the ability to close it with a simple button.

Any help is greatly appreciated.

2
cannot highlight the compass icon. your question is not clear - at least to me. consider to abstract your question to the very essential part...Axel
@Axel This video showcases the issue, youtube.com/watch?v=w3Yrz8eTJiA&feature=youtu.be I want to be able to close the popup with the X icon.Zecele

2 Answers

1
votes

You just need to add any functionality to the existing close button. Your eventHandler already contains logic for showing / hiding the UI, so just add a listener to the close button:

let closeBtn = document.getElementById("close") one close button
closeBtn.addEventListener(this.data.trigger, this.eventHandler.bind(this))

When clicked - it will hide the UI.

However, there are more elements with the ui-modal component, and their eventHandler trigger the setAttribute("visible", "") part.

The easiest way to deal with this would be

closeBtn.addEventListener(this.data.trigger, e => {
  this.el.setAttribute("visible", "false")
})

let the close button hide the element, nothing more to be done here.


This is valid:

if (this.el.getAttribute("visible") {
  // hide
} else {
  // show
} 

as well as this:

// toggle visibility
this.el.setAttribute("visible", !this.el.getAttribute("visible")

You can check it out in this fiddle.

0
votes

Its very hard to debug your issue but there is one thing thats looking "not right" to me!

Your event handler validates this.el.getAttribute('visible') against true and false as booleans but getAttribute will always return a string (which would be 'true' and 'false' in this particular case) or null if the attribute does not exist.

So you should validate like this at the eventHandler part:

if ( this.el.getAttribute('visible') === 'false' ) { // validate against 'false' instead of false
    /* ... */
    this.el.setAttribute('visible', 'true'); // set to 'true' instead of true
} else if ( this.el.getAttribute('visible') === 'true' ) { // validate against 'true' instead of true
    /* ... */
    this.el.setAttribute('visible', 'false'); // set to 'false' instead of false
}

But after further inspection I noticed that actually the A-Frame(work) seems not to set elements attributeValue of attributeName visible to "true"|"false".
Instead if an element is visible its set to visible="" and if its invisible its set to visible="false". So only if this is true you should do it like this:

if ( this.el.getAttribute('visible') === 'false' ) { // validate against 'false' instead of false
    /* ... */
    this.el.setAttribute('visible', ''); // set to '' instead of true
} else if ( this.el.getAttribute('visible') === '' ) { // validate against '' instead of false
    /* ... */
    this.el.setAttribute('visible', 'false'); // set to 'false' instead of false
}