How to force React Component to re-render? - javascript

We are developing one POC in which, we are displaying the list of properties and we displayed respective property details in bootstrap modal popup on click of property title.
We have following React components with the hierarchy:
1 PropertyBox
1.1 PropertyList
1.1.1 PropertyInfo
1.2 PropertyDetails in Bootstrap Modal popup HTML.
The render method of PropertyBox contains following code.
render() {
return (
<div id="property-box">
<PropertyListComponent>
<div class="modal fade" id="myModal">
<div class="modal-dialog modal-lg modal-box-large">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body modal-max-height">
{propertyDetailsElement}
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>;
In property details component there are two bootstrap 4 tabs
1. Overview (by default active)
2. ContactUs
The issue is,
Consider I opened the property details popup by clicking the Property title, and go the Contact Us tab and closed the popup.
After that I clicked on Next property title to see its property details. In that case, popup opens, respective property details are displayed but the Contact Us tab is displayed as active.
So to solve the issue I tried to re-render the PropertyDetails component using method "componentWillReceiveProps"
class PropertyDetail extends React.Component {
constructor(props) {
super(props)
// in state we have stored the images as well as current index of image and translate value
this.state = {
property: this.props.data
}
}
componentWillReceiveProps(nextProps) {
this.setState({
property: nextProps.data
})
}
render() {return (<HTML for Proeperty Details>);
}
}
I have cross verified that whether the method "componentWillReceiveProps" is called every time when I click on PropertyTitle to open the Popup, and yes it is called every time. But issue is not solved.
I am expecting that when Property details popup is opened every time the default active tab should be the Overview tab.
Is there any solution ?

There are two ways you can achieve this.
1) when you change the property add a default function called
componentWillUnMount it will remove the component from dom and it will reset its properties
or you can use
In your component, you can call this.forceUpdate() method to force a rerender.
2) The second one is passing a key to the component whenever you change the property it will update the key passing to component so every time, so you open up a property new key, will be passed and the new component instance will be opened and you will not face this problem again

Related

Vue/JavaScript - Stop 'preventDefault' from affecting child components

I am trying to create a modal dialog in Vue. When the dialog is open, I want the page scrolling to be disabled but the user should still be able to scroll the dialog, and I was trying to achieve this with preventDefault. My component looks like this:
<!--Modal.vue-->
<template>
<div v-show="open" class="modal" #scroll.stop.prevent #wheel.stop.prevent>
<div class="mask"></div>
<div class="overlay">
<div class="dialog">
<button #click="$emit('close')">CLOSE</button>
<Paragraphs />
</div>
</div>
</div>
</template>
<script>
import Paragraphs from "./Paragraphs";
export default {
components: {
Paragraphs,
},
props: {
open: Boolean,
},
};
</script>
<!--some scoped CSS here-->
Full working example on the sandbox https://codesandbox.io/s/optimistic-pond-3zrxsf
The problem is that while this arrangement is preventing page scrolling, it is also freezing scrolling on the dialog itself, which I don't want. And apparently stopPropagation only prevents bubbling up, but not down the DOM tree, so that isn't helping either. What can I do to achieve this?
Note: I do not want to set the overflow-y property of the body tag as that takes away the scrollbars completely and has a jittery effect of everything shifting to the side by a few pixels when the dialog is opened or closed.

Uikit Modal not destroying when route is changed (Angular)

What do I want?
I want to destroy Modals containing my Angular components to be closed and destroyed so it does produce side-effects when I am changing routes (For example using the browser back button).
Actual Results
When changing routes using my app's Navbar, either the Modal stays in the DOM and I am not able to scroll anything on the screen or The Modal simply does not close.
Artifacts such as which should be removed when we close the modal are still present.
I have tried using
UIkit.modal(myModalId).$destroy(true) to remove the modal from dom.
Jquery $(modalId).remove(); Modal removed from DOM but when we go back to the modal page, the Buttons are not triggering the modals.
My Code
Button that Opens Modal
<button uk-toggle="target: #myModalId">Open Modal</button>
Modal template
<div id="myModalId" class="uk-flex-top acc-modal" uk-modal="esc-close: false; bg-close: false; stacked: true; cls-page: 'acc-modal-page';">
<div class="uk-modal-dialog uk-modal-body uk-margin-auto-vertical" style="width: 431.6px !important; ">
<button class="uk-modal-close-default uk-close-large" type="button" id="close-event" uk-close></button>
<h2 class="uk-modal-title">
Modal Title</h2>
<My-Child-Component (newItemEvent)="updateDataAfterChild($event)" #MyChildComponent></My-Child-Component>
</div>
</div>
Hide and Destroy modal when route component destroys.
destroyModal(modalId: string){
const modal = uikit.modal(modalId);
modal.hide();
modal.$destroy(true);
}
ngOnDestroy(){
try{
this.destroyModal('#'+myModalId);
}catch(err){
console.log(err);
}
}
Use routerLink and <router-outlet></router-outlet>.
You can do something like this.
<button mat-flat-button color="primary" routerLink="/login">Login</button>
<button mat-flat-button color="primary" routerLink="/signup">Signup</button>
<router-outlet></router-outlet>
Your Components will show in place of <router-outlet></router-outlet> and they will destroy previous component. [Source]
Thoughts:
I believe this way of routing is done because of the 'nature' of the Single Page Applications.

Ember JS: Call component action from another component

I am new to ember JS and after looking through the doc I still have no idea or don't understand how to achieve the following.
I have a navbar component that includes a menu button component
//components/nav-bar.hbs
<nav>
<LinkTo class="btn-1" #route="contact"><span>Contact</span></LinkTo>
<LinkTo class="btn-1" #route="about"><span>About</span></LinkTo>
<MenuButton>Menu</MenuButton>
</nav>
When this button is clicked I would like to toggle another component which is not a parent nor a child of menu-button component, nor of the nav-bar component
//components/nav-aside.hbs
<div class="core_page_cover">
</div>
<aside class="core_menu_aside">
</aside>
//components/nav-aside.js
import Component from "#glimmer/component";
import { action } from "#ember/object";
export default class NavAsideComponent extends Component {
#action
toggle() {
//toggle expanded | retracted class
}
}
I have no idea how to call the toggle action when clicking on the button and I guess I am missing something...
The components are encapsulated like so
// .--------------navbar.hbs-------------- //
// <nav>
// link link link link link link toggle-button //
// </nav>
// <MenuAside/>
Thanks a lot.
The solution here is to move the state and the action to the common ancestor.
It seems you have 3 components:
navbar
nav-bar
nav-aside
Where basically navbar encapsulates both nav-bar and nav-aside:
so you have basically this in your navbar:
<NavBar />
<NavAside />
and inside the nav-bar you have a button that should toggle if something inside nav-aside is shown.
Then the solution is to keep that information on the wrapping navbar component:
class NavbarComponent extends Component {
#tracked showSomethingInAside = false;
#action
toggleShowSomethingInAside() {
this.showSomethingInAside = !this.showSomethingInAside;
}
}
And use it like this to call your components in navbar:
<NavBar #toggleSomethingInAside={{this.toggleShowSomethingInAside}} />
<NavAside #showSomethingInAside={{this.showSomethingInAside}} />
Then inside nav-bar you can use the action:
<button type="button" {{on "click" #toggleSomethingInAside}}>
show something in aside
</button>
And inside nav-aside you can use the boolean:
{{#if #showSomethingInAside}}
This can be toggled by the button in the other component
{{/if}}
So you see the solution is to always keep the state in the right place. If multiple components share a state (because one changes it and the other reads it) that state belongs in neither component but a common ancestor component.

How to update v-if with data?

I'm creating a simple app with vueJS, but I have some trouble with reactivity.
When an user connects to the app he gets a JWT, I store this JWT in my localstorage. And for verifying if a user is logged I just check the token presence.
First of all, is this a good method?
Now I'm trying to update the navbar, when the user is not logged I have 2 buttons "register" "login", when he is logged I want to have my "disconnect" button showing up and the two others disappear.
I have my navbar component with a "v-if" inside for showing or not the buttons.
Currently I have set a Boolean "isLogged" in my data(), How to make vueJS watch this data and update my component when this data updates?
<div class="navbar-item" v-if="!isLogged">
<div class="buttons">
<a #click="$router.push('/login')" class="button nav-button is-outlined">
CONNEXION
</a>
<a #click="$router.push('/register')" class="button nav-button is-outlined">
INSCRIPTION
</a>
</div>
</div>
<a #click="disconnect" class="navbar-item" v-if="isLogged">
Déconnexion
</a>
data() {
return {
isLogged: this.$jwt.hasToken()
}
}
I'd like to have my navbar updating without have to refresh the component.
Use a computed value instead data.
computed: {
isLogged() {
return this.$jwt.hasToken()
}
}

Adding single Angular-4 component multiple times inside HTML page

We are developing an application in Adobe AEM using angular 4.
Due to our tool limitation we are not able to add a component inside another component by using ng-selector (parent-child structure).
So currently we are creating the parent Component in HTML and including the Angular components inside by using AEM(tool) feature.
In one of the scenario we need to add a single component multiple times in the HTML page but then we are not able to target the each component to show/hide.
For example.
Template in Component1 :
<div *ngif="dynamicvalue">
<div>show</div>
</div>
My HTMl will look like below.
<div *ngif="dynamicvalue"> <!-- Component1 added for the 1st time-->
<div>show</div>
</div>
<div *ngif="dynamicvalue"> <!-- Component1 added for the 2nd time-->
<div>show</div>
</div>
<div *ngif="dynamicvalue"> <!-- Component1 added for the 3rd time-->
<div>show</div>
</div>
In the above scenario :
1.How can I target only the Component1 added at the 1st position to show/hide?
2.How can I target Component1 added at 1st & 2nd position to show/hide?

Categories