react onload reference to components rendered HTML - html

I am making a react component that acts as a tablist, and it contains many tab components inside of it. I want to make an onload function in the tablist so it will reach out and link to its child tabs, but I can't figure out how to send the tablist's location to the function so the function will know which node to start at.
For other events, e.g. onclick, I can send event.target, but for this idk.
Example code, if it helps
const Tabs = ({ list, children, ignoreSession = false }: TabsProps) => {
window.addEventListener('load',initTabs(this.nodePosition)); //<-what I can't figure out
return (
<div
className={`wb-tabs`}
>
<ul role="tablist" className="generated" />
<div className="tabpanels">{children}</div>
</div>
);
};
export default Tabs;```

Related

Trying to get an overlay to toggle on a repeating element. Can't use getElementByID

As per the title I want an overlay to trigger when an image is clicked on, but I then want it to disappear if anywhere other than 3 buttons on the overlay are clicked.
Unfortunately using getElementbyID won't work as the items repeat on a masonry layout.
<Masonry
breakpointCols={breakpointColumnsObj}
className="my-masonry-grid"
columnClassName="my-masonry-grid_column">
{this.state.data.map((data) => (
<div>
<div className="tilebutton" key="" style={{width:'100%',position:'relative'}} href={data.URL} >
<div className="tileoverlay" id="overlay" onClick={overlayoff} onclickout key={data.URL} style={{display:'none',width:'100%',zindex:'2',position:'absolute'}}>
<a className="button1" href={data.URL} onClick>{data.Name}</a>
<a className="button2" href={data.CompURL}>{data.Company}</a>
<a className="button3" href={'instagram.com/'+data.insta}>{data.Company}<img src="\img\Icons\instagram.svg" className='instalogo'/></a>
</div>
<img src={data.img} onClick={overlayon} style={{width:'100%'}}/>
</div>
</div>
))}
</Masonry>
)
function overlayon() {
document.getElementById("overlay").style.display = "block";
}
function overlayoff() {
document.getElementById("overlay").style.display = "none";
}
Unfortunately using the id "overlay" means if I click any version of the masonry it will trigger the overlay on the first image. Is there some way to:
a) identify the element clicked so it will be the one with the toggling overlay
b) have an "onclickout" I could apply to the overlay's buttons
this is about 5 days into my first ever web build so frankly I haven't got a clue what I am doing - any help is appreciated.
Thanks in advance.
The idioms used in React discourages you to manipulate the DOM directly, unless you are doing something special, such as animation. And thus I don't recommend "identifying the element clicked".
With that said, you can manipulate the data, and trigger a redraw accordingly, by invoking some setSate function (in the example below, I've defined a setShouldShowOverlay, that, when invoked, will result in a redraw).
What I recommend is for you to pull out the code inside this.state.data.map() into its own component, like so:
import React, { useState } from 'react';
function Data({ data }) {
const [ shouldShowOverlay, setShouldShowOverlay ] = useState(false);
return (
<div>
<div className="tilebutton" key="" style={{width:'100%',position:'relative'}} href={data.URL} >
<div className="tileoverlay" id="overlay" onClick={() => { setShouldShowOverlay(false); }} onclickout key={data.URL} style={{display:'none',width:'100%',zindex:'2',position:'absolute'}}>
<a className="button1" href={data.URL} onClick>{data.Name}</a>
<a className="button2" href={data.CompURL}>{data.Company}</a>
<a className="button3" href={'instagram.com/'+data.insta}>{data.Company}<img src="\img\Icons\instagram.svg" className='instalogo'/></a>
</div>
<img src={data.img} onClick={() => {
setShouldShowOverlay(true);
}} style={{width:'100%'}}/>
</div>
</div>
);
}
Then finally, update your Masonry code like so:
<Masonry
breakpointCols={breakpointColumnsObj}
className="my-masonry-grid"
columnClassName="my-masonry-grid_column">
{this.state.data.map((data) => (
<Data data={data} />
))}
</Masonry>

Mouse Hover function to refer different <div id> on same Vue.js function

I have two div id in ".html" file where I've defined mouseover property.
<div id="app">
<img class="img-responsive img-full" v-bind:src="imgData" #mouseover="imgData = imgData_1">
</div>
<div id="app1">
<img class="img-responsive img-full" v-bind:src="imgData_c" #mouseover="imgData_c = imgData_a">
</div>
In my app.js I've mentioned the below code
var app = new Vue({
el:'#app',
data:{
imgData:'img/blog_grid_3.jpg',
imgData_1:'img/blog_grid_1.jpg',
imgData_2:'img/blog_grid_2.jpg'
}
})
var app1 = new Vue({
el:'#app1',
data:{
imgData_a:'img/blog_grid_1.jpg',
imgData_b:'img/blog_grid_3.jpg',
imgData_c:'img/blog_grid_2.jpg'
}
})
Is it possible if I do a mouse hover in the image on div id="app" (1st 'div') then the image on div id="app1" (2nd 'div') change?.
You can use the built-in event bus in a Vue instance. Listen to changes and emit events on a third Vue instance. You just need to make sure, that you can access this third Vue intance in both of your apps. Here is an article to read more about this feature: article
Here is an example on how to use such an EventBus:
const EventBus = new Vue();
// subscribe to the event 'some-event' and add a handler function
EventBus.$on('some-event', data => {
console.log('"some-event" was called via event.');
console.log(data);
});
// actually emit the event with some payload
EventBus.$emit('some-event', { test: 123 });
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
You may also want to ask yourself if it is really necessary to have two separate Vue instances running. Many use cases can be handled within the same Vue instance. You might want to look into topics about components and routing.
Communicating between components is also possible with a global state. You could e.g. use Vuex to have your state at one place and access this global state from your components.

How to close an Angular2 modal with a boolean?

I'm new to html and Angular2. Any help with this problem would be much appreciated.
I am placing a form component inside a ng2-modal and I would like the modal to close when the form returns a boolean from an event.
The form is for adding a new class to a database. Its first usage is on another page where it is not inside a modal.
There, upon clicking cancel/submit in the component, I have it return true and then redirect to another url.
For the new implementation I want the modal to close when the form returns true. The problem is that the save/cancel buttons are in the component containing the form. So I can't just use the modal's click event to close it.
Here is my current code:
<modal #addNewClassModal>
<modal-header>
<h4 class="modal-title"><i class="fa fa-cube"></i> Add a new class</h4>
</modal-header>
<modal-content>
<div>
<add-new-class (closeModal)="finishAddingNewClass($event)">
</add-new-class>
</div>
</modal-content>
</modal>
My problem is that I can't figure out how to get the modals close() method to rely on the boolean.
I've tried putting closeModal="addNewClassModal.close()" in different places and switching around the syntax but its not working and I can't find anything online.
You can pass a reference to addNewClassModal to your AddNewClass component:
<add-new-class [modal]="addNewClassModal">
</add-new-class>
And in your AddNewClass component add Input() for modal:
import { Input } from '#angular/core';
import { ModalDirective } from 'ng2-bootstrap/components/modal';
#Input()
modal: ModalDirective; // you can also set type to any instead of ModalDirective
Then in your component you can close modal with hide() function:
this.modal.hide();

Parent/child click relationships in AngularJS directives

I have a custom directive placed on a Kendo UI treeview widget.
It seems to be working fine side-by-side, except that I'm trying to simply display the custom icons next to the tree node which is clicked on (see sample image below).
So my directive is data-toggle-me, placed next to the Kendo k-template directive as follows :
<div class="reports-tree" kendo-tree-view="nav.treeview"
k-options="nav.treeOptions"
k-data-source="nav.reportsTreeDataSource"
k-on-change="nav.onTreeSelect(dataItem)" >
<span class="tree-node" k-template data-toggle-tree-icons>{{dataItem.text}}</span>
</div>
and the directive code here inserts some custom icons next to the tree node when a user clicks on that tree node :
.directive('toggleMe', function ($compile) {
// Kendo treeview, use the k-template directive to embed a span.
// Icons appear on Click event.
return {
restrict: 'AE',
transclude: true,
template: '<span ng-show="nav.displayIcons" id="myIcons" class="reptIcons" style="display:none;width:50px;align:right;">' +
' <a title="add new folder" ng-click="nav.addAfter(nav.selectedItem)"><i class="fa fa-folder-open"></i></a> ' +
'<a title="add report here" ng-click="nav.addBelow(nav.selectedItem)"><i class="fa fa-plus"></i></a> ' +
'<a title="remove" ng-click="nav.remove(nav.selectedItem)"><i class="fa fa-remove"></i></a> ' +
'<a title="rename" onclick="showRename(this);"><i class="fa fa-pencil"></i></a>' +
'</span>',
link: function (scope, elem, attrs) {
var icons = elem.find("#myIcons");
elem.on('click', function (e) {
$('.reptIcons').css('display', 'none');
icons.css("display", "inline");
icons.css("margin-left", "5px");
});
}
}
})
My biggest problem at this point is getting the icons to appear on the treenode which is clicked on. Then once the user clicks on a different node, the icons will only render again on the newly-clicked node.
This fiddle represents a partially-working example but the icons are appearing on every single treenode - click tree item to show icons
**** UPDATED TREE IMAGE - All child nodes now show icons (not what I want) ****
I'm not sure to understand your issue, you should try to reduce the code to the minimum and have a snippet/jsfiddle that works.
If all you want is not trigger click events when $scope.disableParentClick is set to true, simply add
elem.on('click', function (e) {
// Do not execute click event if disabled
if (!$scope.disableParentClick) { return; }
...
});
Now that seems all not very angular friendly to me. You should externalize your HTML in either the template or templateUrl of your directive, potentially adding to it a ng-if="displayTemplate" which would only display the node when a click would set $scope.displayTemplate = true;
Also, instead of listening for click events this way, you should use the ng-click directive. Everything is doable with directives. I can give more information when you better understand your problem: I suspect you are not approaching it the right way.
UPDATE: if all you want is display the icons list of the clicked element, you could do it way easier. You actually don't need the toggle-me directive, but even if you keep it you can solve all your troubles the angular-way, which is by using ng-click, ng-repeat, etc. Please have a look at the following jsFiffle to see one way of doing that. There are many other ways, but really try using ng-click to avoid troubles:
http://jsfiddle.net/kau9jnoe/
Events in the DOM are always bubbling up. That is a click on a link would trigger an onclick handler on every element up the hierarchy, e.g. also the body element. After all the click happened within body.
The same is true for your directive. Any click within your element triggers its event handler. To circumvent this either attach the event handler somewhere else or ignore clicks from the links.
The event object has a target property that tells you what element initiated the event. So you could do something like this:
elem.on('click', function (e) {
if (e.target.nodeName.toLowerCase() == 'a') return; //ignore click on links

Is it possible to impact visibility of a DOM element outside of view?

My question is very similar to Hide element outside the ng-view DOM based on route
If possible I would like to have a TypeScript solution that allows to assign a value to ng-show property of an element outside of ng-view from my existing controllers.
I tried assigning a value to $rootScope property but it was not visible in index.html outside of the view.
Here's what I tried in controller constructors:
$rootScope.isForm = "true"; in one, and $rootScope.isForm = "false"; in another.
Inside my index.html I have the following:
<div class="navbar navbar-inverse">
....
<form <form class="navbar-form navbar-input-group" ng-show="$rootScope.IsForm">
...
</form>
...
</div>
...
<div "ng-view">
...
</div>
How should I go about it? Is there still a solution using $rootScope?
You can get the $rootScope inside your controllers and modify it there. i.e.
class FooController{
static $inject = ['$rootScope'];
constructor(public $rootScope){
// You can also do this based on some user action.
// Just a demo of how :
this.$rootScope.IsForm = true;
}
}