How to let one component correspond with the other for a specific function - html

I've got a component where I click a color of a machine, when I change colors, the machine gets loaded with a different color inside a image carousel.
Now I also created a component in the bottom with a image gallery of the same machine. How can I make it that the image gallery also changes color when I click the color button in the top of the page?
Important notice: The two components are not in the same parent component but they do load in the same machine images already, so the methods are not wrong I believe.
this is the clickable color button:
<li
v-for="(color, index) in machine.content[0].machine_colors"
:key="color.color_slug"
v-if="color.inStock"
v-on:click="selectColor(index)"
v-bind:class="{ active: (color.color_slug === selectedColor.color_slug)}">
<img v-bind:src="color.color_dash">
</li>
this is the component that changes color:
<div class="product__carousel">
<Carousel showIcon v-if="selectedColor" :machineColor="selectedColor"/> <!-- Image carousel gets loaded in -->
</div>
and the component that needs to change color but does not:
<div id="tab-two-panel" class="panel">
<footerGallery v-if="selectedColor && machine" :machineColor="selectedColor"/>
</div>
Heres the script of the partent component:
export default {
name: 'aboutMachine',
components: {
Collapse,
footerGallery,
},
data() {
return{
selectedColor: this.getMachineColorContent(),
}
},
props: {
main: {
default () {
return {};
},
},
machine: {
default () {
return {};
},
},
},
methods: {
getMachineColorContent() {
if (this.selectedColor) {
return null;
}
return this.machine.content[0].machine_colors[0];
},
selectColor(index) {
this.selectedColor = this.machine.content[0].machine_colors[index];
},
},
}
and the component itself:
export default {
name: 'footerGallery',
props: {
showIcon: Boolean,
machineColor: {
default () {
return {};
},
},
},
data() {
return {
highLightedThumbIndex: 0,
isActive: undefined,
};
},
created() {
this.highLightedThumbIndex = this.highLightedThumbIndex || 0;
},
methods: {
selectThumb(index) {
this.highLightedThumbIndex = index;
},
},
};
This is my main.js
import Vue from 'vue';
import VueYouTubeEmbed from 'vue-youtube-embed'
import FontAwesome from './libs/fa';
import App from './App';
const eventHub = new Vue();
Vue.use(VueYouTubeEmbed);
Vue.component('font-awesome-icon', FontAwesome);
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
components: { App },
template: '<App/>',
});

I would use events to accomplish this. The migration guide to Vue2 has a good short explanation of how to do simple event routing without using a full Vuex solution. In your case, you would declare a global event hub in one of your js files:
var eventHub = new Vue();
In your selectColor method you would emit the index selected:
selectColor(index) {
this.selectedColor = this.machine.content[0].machine_colors[index];
eventHub.$emit("select-color",index);
}
And in the footer, you would register a listener for the select-color event that calls selectThumb with the payload of the event (which is the selected index):
created() {
this.highLightedThumbIndex = this.highLightedThumbIndex || 0;
eventHub.$on("select-color",this.selectThumb);
}

Related

how I can fix overlap issue in stackbarchart using vue-chartjs

I'm using latest vue-chartjs package with vue3 to create stackbarchart. I've shown the stackbarchart on my app but it's labels are overlapping. I need to know which property can add in options that can fix my issue.
<template>
<Bar
v-if="chartData != null"
:key="id"
:data="chartData"
:options="chartOptions"
/>
</template>
<script>
import { Bar, getElementAtEvent } from "vue-chartjs";
import ChartJSPluginDatalabels from "chartjs-plugin-datalabels";
import uniqueId from "lodash.uniqueid";
import { drilldown } from "#/views/Reports/js/drilldown";
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
BarElement,
CategoryScale,
LinearScale,
ArcElement
} from "chart.js";
ChartJS.register(
CategoryScale,
LinearScale,
BarElement,
Title,
Tooltip,
Legend,
ArcElement,
ChartJSPluginDatalabels
);
export default {
name: "BarChartStacked",
components: {
Bar,
},
props: ["data", "options", "reportData", "eventInfo", "item", "duringDay"],
data() {
return {
id: null,
};
},
computed:{
chartData() { return this.data; /* mutable chart data */ },
chartOptions() { return this.options; /* mutable chart options */ }
},
mounted() {
this.id = uniqueId();
this.chartOptions.plugins.responsive = true;
if (this.reportData && this.reportData.dataFilter) {
if (this.item.conditions) {
// change cursor to pointer if element is clickable
this.chartOptions.hover = {
onHover: function(e) {
var point =getElementAtEvent(e);
if (point.length) e.target.style.cursor = 'pointer';
else e.target.style.cursor = 'default';
}
}
this.chartOptions.onClick = this.handle;
}
} else {
this.chartOptions.hover = {}
}
},
The stackbarchart should display value for the top most graph only like mention in the picture.

2 V-If Statements in the same div?

I am attempting to put two conditions into one div, but since I am new to coding, I am not sure where to go from here. Basically what my code is doing is displaying a part table constantly, but I only want to display the table when there are results found. When the no results div displays, I would like the table to not display. If any advice could be spared, it would be greatly appreciated. Here is the code....
<keep-alive>
<PartsTable style="grid-area: contentArea" v-if="displayStore.cardView" />
</keep-alive>
<div id="noResultsDiv" v-if="partStore.filterQuery && !computedList.length">No Results Found</div>
script
<script lang="ts">
import { defineComponent } from "vue";
import { mapStores } from 'pinia'
import PartsTable from "../components/PartsTable.vue";
import ActionButton from "../components/ActionButton.vue";
import PartCardHolder from "../components/PartCardHolder.vue";
import { useDisplayStore } from "../stores/display-store";
import { usePartStore } from "../stores/part-store";
import { PartDefinition } from "../types/PartDefinition";
export default defineComponent({
name: "Home",
components: {
PartsTable,
ActionButton,
PartCardHolder,
},
data() {
return {
pageCount: 50 as number,
emptyStore: false as boolean
}
},
computed: {
...mapStores(useDisplayStore, usePartStore),
computedList(): PartDefinition[] {
return this.partStore.filteredList.slice(0, this.pageCount);
},
},
methods: {
addPart(): void {
this.$router.push({
path: `/add`,
});
},
viewPart(id: PartDefinition["id"]): void {
this.$router.push({
path: `/view/${id}`,
});
},
async updateStorage() {
sessionStorage.setItem("cardView", this.displayStore.cardView.toString())
},
},
async mounted() {
if (sessionStorage.getItem("cardView") == "true") {
this.displayStore.cardView = true
sessionStorage.setItem("cardView", "true")
} else {
this.displayStore.cardView = false
sessionStorage.setItem("cardView", "false")
}
console.log(sessionStorage.getItem("cardView"))
},
unmounted() {
this.partStore.filterQuery = ""
},
});
</script>
You can use vue.js Conditional Rendering v-if/v-else to achieve.
<div v-if="computedList.length">
// Your parts table will come here.
</div>
<div v-else>
// No results div will display here
</div>
I just gave you a way to achieve the requirement. You can modify the condition as per your need.

Mapping through an Array of Images created in a local JSON File and rendering it

I am learning RN and I am having trouble setting up a mapping method to go through an array of images of some players that I created in a local JSON file, and render them in their respective profile pages.
This is how I have set my json.
//PlayerImages.js
const PlayerImages = [
{
id: "1",
name: "Cristiano Ronaldo",
images:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "2",
name: "Lionel Messi",
images:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "3",
name: "Neymar",
images: mages:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
},
{
id: "4",
name: "Gabriel de Jesus",
images:["https://i.pinimg.com/474x/f1/36/ca/f136ca04817e60fa12f4a5680101ff8b.jpg",
"https://i.pinimg.com/474x/b1/da/e2/b1dae2fe6ca1620e5d1949a2dcd33a0c.jpg",
"https://i.pinimg.com/564x/7b/53/32/7b5332ef6a981b3c54e855495ea1c828.jpg"]
},
{
id: "5",
name: "Roberto Firmino",
images:mages:["https://www.thesun.co.uk/wp-content/uploads/2019/05/NINTCHDBPICT000485852530.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg",
"https://e00-marca.uecdn.es/assets/multimedia/imagenes/2019/05/18/15582064666477.jpg"]
}
]
export default PlayerImages;
This is how I have the ImageGallery component set up. Unfortunately, the way I have componentDidMount set up, shows Cristiano Ronaldos images in all profiles. How can I map it in order to make sure that each profile has the pictures of that particular player when you tap the gallery button on their profile?
//ImageGallery.js
import React, { Component } from "react";
import { StyleSheet, Text, View } from "react-native";
import { SliderBox } from "react-native-image-slider-box";
import { withNavigation } from "react-navigation";
import PlayerImages from "../Data/PlayerImages";
class ImageGallery extends React.Component {
static navigationOptions = {
title: "Player Gallery",
headerStyle: {
backgroundColor: "#53b4e6"
},
headerTintColor: "#f6c945",
headerTitleStyle: "bold"
};
constructor(props) {
super(props);
this.state = {
images: []
};
}
componentDidMount() {
let images = PlayerImages[0].images;
this.setState({ images });
}
render() {
return (
<View style={styles.container}>
<SliderBox
images={this.state.images}
sliderBoxHeight={900}
onCurrentImagePressed={index =>
console.warn(`image ${index} pressed`)
}
dotColor="yellow"
inactiveDotColor="white"
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
}
});
export default withNavigation(ImageGallery);
Finally, when you are on the players profile, you should have access to their gallery by tapping the button in the header. As I mentioned earlier in the post, when you tap it, you get only the images of Cristiano Ronaldo.
//PlayerProfile.js
headerRight: (
<Button
onPress={() => navigation.navigate("ImageGallery")}
title="Gallery"
color="#f6c945"
/>
)
Pass the id of the player or the index of the player you want to display images of using navigation parameters , then use it to get the images of the player, right now you are using images at the 0th index of array.
componentDidMount() {
let images = PlayerImages[0].images;
this.setState({ images });
}
change this to
componentDidMount() {
let images = PlayerImages[index].images; //index is the index of the player whose images you want to show
this.setState({ images });
}

Vuejs not passing property to mounted

Have the following code:
export default new Router({
routes: [
{
path: '/noticia/:id',
name: 'Noticia',
component: Noticia,
props: true
}
]
})
export default {
name: 'Noticia',
data () {
return {}
},
props: ['id'],
computed: {
noticia () {
return this.$store.getters.noticia
}
},
mounted: function () {
this.$nextTick(function () {
console.log(id)
// Code that will run only after the
// entire view has been rendered
})
}
}
<div>{{id}}</div>
The problem is {{id}} is showed by html div, but it isn't passed to 'mounted', so, i cannot run my 'console.log(id)' (as it will run a code to bring data and put it into the computed).
I have other code running with the same data, running wheel, cannot understand the error
mounted() {
console.log( this.id )
}
To get it working on mounted, just did:
this.id instead of just id

onError in img tag in React

I want to replace a broken link with a default image in react. I'd typically use onerror for this but it is not working as expected. Specifically, I get repeated errors of "Cannot update during an existing state transition (such as within render)." Eventually, the default image appears, but it takes a long time (many prints of this error). This is a very similar question asked here: react.js Replace img src onerror. I tried this solution (top one, not using jQuery) but it causes the error described. I guess onError must be getting triggered continually, thus causing the constant rerendering. Any alternative solutions/fixes?
import React from 'react';
import { connect } from 'react-redux';
//import AddImageModal from '../components/AddImageModal.js';
import Button from 'react-bootstrap/lib/Button';
//import { getPostsByUserId } from 'actions'
import Posts from '../components/Posts.js';
var Modal = require('react-modal');
require('../../styles/AddImageModal.scss');
import { save_post } from '../actions';
const customStyles = {
content : {
top : '50%',
left : '50%',
right : 'auto',
bottom : 'auto',
marginRight : '-50%',
transform : 'translate(-50%, -50%)'
}
};
var MyWallScreen = React.createClass({
getInitialState: function() {
return {
modalIsOpen: false,
imageUrl: ""
};
},
openModal: function() {
this.setState({modalIsOpen: true});
},
afterOpenModal: function() {
// references are now sync'd and can be accessed.
this.refs.subtitle.style.color = '#f00';
},
closeModal: function() {
this.setState({modalIsOpen: false});
},
setUrl: function(e,val)
{
if (e.keyCode === 13)
{
this.setState({
imageUrl: val
});
}
},
resetImageUrl: function()
{
this.setState({
imageUrl: ""
});
},
onError: function() {
this.setState({
imageUrl: "default.jpg"
});
},
render: function() {
const { userPosts, dispatch } = this.props;
return (
<div>
<button onClick={this.openModal}>Add Image</button>
{/* The meat of the modal. */}
<Modal
isOpen={this.state.modalIsOpen}
onAfterOpen={this.afterOpenModal}
onRequestClose={this.closeModal}
style={customStyles} >
<div className="modalBox">
<h2 className="modalBanner">Add an image link</h2>
<input ref="urlInput"
className="modalInput"
onKeyDown={e=>this.setUrl(e,this.refs.urlInput.value)}/>
{this.state.imageUrl ?
<img className="modalImage"
src={this.state.imageUrl}
onError={this.onError()}/>
:<div className="modalImage"></div>
}
<div>
<Button className="modalButton" bsStyle = "success"
onClick = {() => {
dispatch(save_post(0,this.state.imageUrl));
this.closeModal();
this.resetImageUrl();
}}>
Post
</Button>
<Button className="modalButton" bsStyle = "danger"
onClick = {() => {
this.closeModal();
this.resetImageUrl();
}}>
Cancel
</Button>
</div>
</div>
</Modal>
<Posts posts={userPosts}/>
</div>
);
}
});
function mapStateToProps(state, ownProps) {
return {
userPosts: state.posts[0]
}
}
MyWallScreen = connect(mapStateToProps)(MyWallScreen);
export default MyWallScreen;
The code is calling this.onError rather than passing a reference to it. Every call to render is calling this.onError(). Remove the parentheses, and see if that fixes it:
<img className="modalImage"
src={this.state.imageUrl}
onError={this.onError()}/> // `onError` is being called here
Fixed version:
<img className="modalImage"
src={this.state.imageUrl}
onError={this.onError}/> // `onError` is being passed as a reference here
You can replace the image broken link without keeping image urls in state.
<img
onError={(event)=>event.target.setAttribute("src","default-image-link")}
src="image-broken-link"
/>
I tried this way and it works for me hope this will work for you.
Make sure to put the below useState within same function where u used img tag.
const [error, setError] = useState(false);
<img src={`${error ? DefaultLogo
:`${AgentApiURL}/publicservices/images/${props.item[0]}`}`}
alt="plating"
onError={() => setError(true) }
/>