Simply return a value from another component - javascript

Wondering if you guys can help. I am trying to create a generic component which when called, will return a value.
The code currently stands as follows:
import React, {Component} from 'react'
class Clients extends Component {
render () {
var userEnum = {
SMALL: 1,
MEDIUM: 2,
LARGE: 3,
properties: {
1: {name: "Admin", value: 1},
2: {name: "Manager", value: 2},
3: {name: "Standard", value: 3}
}
};
const clientName = (value) => {
return userEnum.properties[value].name
}
return null
}
}
export default Clients
and in another component, I try calling the clientName function (done an import too).
import ClientHelper from '../../helpers/clients'
...
const test = ClientHelper.clientName(2)
console.log(test)
I should expect a return value of 'Manager' but I get
TypeError: WEBPACK_IMPORTED_MODULE_9__helpers_clients.a.clientName
is not a function

You are declaring the function clientName inside the render method of the class Clients. This function is only accessible inside it's scope, the render method.
To access the function like you would, by calling the class Clients static method clientName, you should write it like this:
import React, { Component } from 'react'
class Clients extends Component {
static userEnum = {
SMALL: 1,
MEDIUM: 2,
LARGE: 3,
properties: {
1: { name: "Admin", value: 1 },
2: { name: "Manager", value: 2 },
3: { name: "Standard", value: 3 }
}
};
static clientName(value) {
return Clients.userEnum.properties[value].name;
}
render() {
return null;
}
}
export default Clients
If you do not intend to render anything with this class, you do not need react, and can simply create a utility/static class like below:
export default class Clients {
static userEnum = {
SMALL: 1,
MEDIUM: 2,
LARGE: 3,
properties: {
1: { name: "Admin", value: 1 },
2: { name: "Manager", value: 2 },
3: { name: "Standard", value: 3 }
}
};
static clientName(value) {
return Clients.userEnum.properties[value].name;
}
}

the function clientName is not a property of your class, but a local function inside the render function and therefore not accessible from the outside.
To solve this, you have to make clientName as well as your userEnum properties of the Clients object, for example in the constructor:
import React, {Component} from 'react'
class Clients extends Component {
constructor(props){
super(props);
this.userEnum = {
SMALL: 1,
MEDIUM: 2,
LARGE: 3,
properties: {
1: {name: "Admin", value: 1},
2: {name: "Manager", value: 2},
3: {name: "Standard", value: 3}
}
};
}
function clientName (value) {
return this.userEnum.properties[value].name
}
function render () {
return null
}
}
export default Clients

Related

Reactivity in props in Vue3 Composition API?

I'm watching a couple of props on a child component (basicSalaryMin and basicSalaryMax). When the value changes I'm then trying to update a reactive the value on the parent component (data.companyModels which is also passed to the child component as a prop inside allReactiveData).
Child component:
<template>
<div>
{{allReactiveData.companyModels}} // all data is rendered!
</div>
</template>
<script>
import { toRefs, watch, ref, reactive } from "vue";
export default {
name: 'SimPrivate',
props: {
reactiveData: {
required: true,
type: Object
},
},
setup (props, { emit }) {
const allReactiveData = ref(props.reactiveData);
const basicsalaryMin = ref(props.reactiveData.basicsalaryMin);
const basicsalaryMax = ref(props.reactiveData.basicsalaryMax);
const changeCompanyProfit = ref(props.changeCompanyProfit)
watch([basicsalaryMin, basicsalaryMax], ([newBSMin, newBSMax], [prevBSMin, prevBSMax]) =>
{
let wagesArray =[]
wagesArray.push(newBSMin, newBSMax);
adjustAllWorkersSalaries(wagesArray);
allReactiveData.companyModels.forEach(function(company)
//console is saying Uncaught (in promise) TypeError:
Cannot read property 'forEach' of undefined!!
and Can't do anything to the object from this point forward
I then need to add new sub-properties depending on
how many __ranks__ the property companyModel has...
but I'll get to that later
{
for (const [key, value] of Object.entries(company)) {
if (key === 'ranks') {
// if 1 rank add sub-object to companyModel.wages with var basicsalaryMin value called "wages: {1: basicsalaryMin}"
// if 2 ranks add sub-object: "wages:{1: basicsalaryMin, 2: basicsalaryMax }
// if 3 ranks add sub object: "wages...
// as in the model bellow but allowing for more levels
}
}
})
})
return {
allReactiveData,
basicsalaryMin,
basicsalaryMax,
}
}'
Parent component:
<template>
<div>
<input #change="handleMaxSalaries(basicsalaryMax)" id="maxsalaryInput" v-model.number='basicsalaryMax'>
<SimPrivate :reactiveData='reactiveData' #adjustAllWorkersSalaries='adjustAllWorkersSalaries'/>
</div>
</template>
<script>
</script>
import { toRefs, watch, ref, reactive } from "vue";
import SimPrivate from '../views/SimPrivate.vue'
export default {
name: "Simulator",
components: {
Slider,
SimPrivate
},
props: {},
setup( props, {emit}) {
let data = reactive({
avrgProfit: 0,
basicsalaryMin: 3000,
basicsalaryMax: 5000,
TotalUBICreatedPerMonth: 0,
companyModels: [
{ id: 'Big', workers: 250, ranks: 5, companyAvrgProfit: 0, totalWages: Number, wages: {1: '3000', 2: '3500', 3:'4000', 4: '4500', 5: '5000' }},
{ id: 'Medium', workers: 75, ranks: 3, companyAvrgProfit: 0, totalWages: Number, wages: {1: '3000', 2: '4000', 3:'5000' }},
{ id: 'Small', workers: 10, ranks: 2, companyAvrgProfit: 0, totalWages: Number, wages: {1: '3000', 2: '5000' }},
{ id: 'Individual', workers: 1, ranks: 1, companyAvrgProfit: 0, totalWages: Number, wages: {1: '3000'}}}
],
)}
let reactiveData = toRefs(data)
return {
allReactiveData,
basicsalaryMin,
basicsalaryMax,
}
)}
The goal is to then check the value of ranks (which will vary between 1 and 100) and create as many equidistant wage values as needed to match the rank number.
Any thoughts?
If you want to access or modify a ref from your script you need to do
yourref.value.
e.g.
yourref.value = 'Hello'
console.log(yourref.value)
// outputs : 'Hello'
So in your case allReactiveData.value
See docs

How to run a method using v-for in Vue.js?

I want to get the following output for the following data.
・3
・1
and sample data :
export const dummyData = [
{
id: "1",
name: "a",
sub: [
{
id: "1#1",
name: "b",
sub_sub: [
{ id: "1#1#1", name: "b-a" },
{ id: "1#1#2", name: "b-b" },
]
},
{
id: "1#2",
name: "c",
sub_sub: [
{ id: "1#2#1", name: "c-a" },
]
},
]
},
{
id: "2",
name: "d",
sub: [
{
id: "2#1",
name: "e",
sub_sub: [
{ id: "1#2#1", name: "e-a" },
]
}
]
},
]
I want to count how many elements of sub_sub are includes in object "a" and "d".
So, I made the following code.
<template>
<div>
<ul>
<li v-for="item in items" :key="item.i">{{rowSpanCalc(item.id)}}</li>
</ul>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'nuxt-property-decorator'
import { dummyData } from '~/store/dummy'
#Component({})
export default class extends Vue {
items: any = []
created() {
this.items = dummyData
}
rowSpanCalc(item: any) {
const count = item.sub.reduce(
(total: any, curr: any) => total + curr.sub_sub.length,
0
)
return count;
}
}
</script>
I ran my code and got an error in console like
  
  item.sub.reduce is not a function
Could anyone please advise me how to fix this errors?
Methods in the template are used as events handler not for rendering, try to use that method inside a computed property then use that property for render your items :
#Component({})
export default class extends Vue {
items: any = []
created() {
this.items = dummyData
}
get customItems(){
return this.items.map(item=>({...item,count:this.rowSpanCalc(item.id)}))
}
rowSpanCalc(item: any) {
const count = item.sub.reduce(
(total: any, curr: any) => total + curr.sub_sub.length,
0
)
return count;
}
}
template :
...
<li v-for="item in customItems" :key="item.id">{{item.count}}</li>
...

How am I exporting my object incorrectly?

I'd like to know how I'm exporting my object incorrectly? In my view, I'm seeing this error: ./src/context.js
Attempted import error: 'detailProduct' is not exported from './data'.
In the console I indeed see the objects being populated correctly but for some reason it won't render my view because of the aforementioned error. What am I doing wrong?
export const storeProducts = [
{
id: 1,
title: "Crusk Beanie (black)",
img: "img/CruskipBlackBeanie.png",
price: 1,
company: "Cruskip",
info:
"Winter's right around the corner, get your beanie today!",
inCart: false,
count: 0,
total: 0
},
{
id: 3,
title: "Cruskip Short Sleeve T-shirt",
img: "img/CruskipWhiteShortSleeve.jpg",
price: 8,
company: "Cruskip",
info:
"Exclusive Cruskip white t-shirts!",
inCart: false,
count: 0,
total: 0
},
];
let detailProduct = {};
storeProducts.forEach((arrayItem) => {
detailProduct = {
id: arrayItem.id,
title: arrayItem.title,
img: arrayItem.img,
price: arrayItem.price,
company: arrayItem.company,
info: arrayItem.info,
inCart: arrayItem.inCart,
count: arrayItem.count,
total: arrayItem.total
};
console.log(arrayItem);
});
export default detailProduct;
You're likely importing it using braces, but you can't do that for default exports:
// This will work
import detailProduct from './data';
// This won't
import { detailProduct } from '.data';
On the other hand, since storeProducts is a named export, it works the other way around:
// This will work
import { storeProducts } from './data';
// This won't
import storeProducts from './data';

Unable to pull data from a data-attribute in Angular 7

I am attempting to reuse a kendoDropDownListBox and set the data by using a data-attribute in the parent to query the proper data source, combined with a switch case statement. The switch case portion of the code is not included as it works when the proper data is passed to it, I'm just unable to pull the proper data from the data-attribute (if I use buttons to pass the data it works fine)
I have tried a number of methods to pull the attribute including the following
element.dataset[keyname]
element.getAttribute('keyname']
If I do a console.log('element') I can see the proper data, but either of the above two methods come up empty (either null or undefined).
The HTML:
<div [attr.data-message-id]="1"> Listbox Component
<app-listbox></app-listbox>
</div>
The Typescript:
import { Component, OnInit, ElementRef } from '#angular/core';
#Component({
selector: 'app-listbox',
styleUrls: ['./listbox.component.scss'],
template: `
<kendo-dropdownlist style="width:400px;"
[data]="data"
[filterable]="true"
[textField]="'text'"
[valueField]="'value'"
(filterChange)="handleFilter($event)"
>
<ng-template kendoDropDownListNoDataTemplate>
<div>
No data found.
<ng-container *ngIf="filter">Do you want to add new item - '{{ filter }}' ?</ng-container>
<br />
<button *ngIf="filter" class="k-button" (click)="addNew()">Add new item</button>
</div>
</ng-template>
</kendo-dropdownlist>
`
})
export class ListboxComponent {
public filter: string;
public source: Array<{ text: string, value: number }> = [
{ text: "Small", value: 1 },
{ text: "Medium", value: 2 },
{ text: "Large", value: 3 }
];
public data: Array<{ text: string, value: number }>;
messages = [
{
id: 1,
text: "Table1"
},
{
id: 2,
text: "Table2"
},
{
id: 3,
text: "Table3"
},
{
id: 4,
text: "Table4"
}
]
Table1 = [
{ id: 1, text: "small"},
{ id: 2, text: "med"},
{ id: 3, text: "large"},
{ id: 4, text: "XL"},
]
Table2 = [
{ id: 1, text: "ford"},
{ id: 2, text: "dodge"},
{ id: 3, text: "chevy"},
{ id: 4, text: "GM"},
]
Table3 = [
{ id: 1, text: "fiat"},
{ id: 2, text: "audi"},
{ id: 3, text: "Mercedes"},
{ id: 4, text: "BMW"},
]
Table4 = [
{ id: 1, text: "toyota"},
{ id: 2, text: "nissan"},
{ id: 3, text: "datsun"},
{ id: 4, text: "kia"},
]
constructor(private elRef: ElementRef) {
this.data = this.source.slice(0);
}
public addNew(): void {
this.source.push({
text: this.filter,
value: 0
});
this.handleFilter(this.filter);
}
public handleFilter(value) {
this.filter = value;
this.data = this.source.filter((s) => s.text.toLowerCase().indexOf(value.toLowerCase()) !== -1);
}
ngOnInit() {
console.log("OnInit");
console.log("el");
var el = this.elRef.nativeElement.parentElement.dataset;
console.log(el);
console.log("elatt");
var elatt = this.elRef.nativeElement.parentElement.attributes;
console.log(elatt);
console.log("elkey");
var elkey = this.elRef.nativeElement.parentElement.dataset['messageId'];
console.log(elkey);
console.log("att");
var att = this.elRef.nativeElement.parentElement.getAttribute(['data-message-id']);
console.log(att);
}
}
Using the above code, the el variable contains the following:
enter image description here
The elatt variable contains the following:
enter image description here
the elkey variable reports "undefined" and the att variable reports "null".
I'm sure I'm probably doing this the hard way, but being new to Angular, I'm not sure of a better way of doing this.
Ultimately what I'm looking for is a way to reuse the kendoDropdownBox as a component, and pass it the data it needs to display when it is used.
ngOnInit() :
Initialize the directive/component after Angular first displays the data-bound properties and sets the directive/component's input properties.
Called once, after the first ngOnChanges().
ngAfterViewInit() :
Respond after Angular initializes the component's views and child views / the view that a directive is in.
Called once after the first ngAfterContentChecked().
You are not able to retrieve the data attribute from parent because, you are trying to access the parent from ngOnInit event. It should be in ngAfterViewInit Lifecyle event.
Refer the example below.
ParentComponent.html
<div [attr.data-message-id]="1">
<app-test-component></app-test-component>
</div>
ChildComponent.ts
import { Component, OnInit, ElementRef } from '#angular/core';
#Component({
selector: 'app-test-component',
templateUrl: './test-component.component.html',
styleUrls: ['./test-component.component.css']
})
export class TestComponentComponent implements OnInit {
constructor(private elRef: ElementRef) {
}
ngOnInit() {
}
ngAfterViewInit(){
console.log(this.elRef.nativeElement.parentElement);
console.log('message id : ', this.elRef.nativeElement.parentElement.dataset['messageId']);
}
}
Output Log

Issue with dismissing item in reactjs

I am trying to dismiss an item from my array which I have mapped out. I made the onclick button, binded it, and defined the function. However, when I press the dismiss button, the items are still there
I tried to change my object id to different name, change some of the code. I even console.log to see whether my button was working. It was. Just it wasnt deleting the intended item.
import React from "react";
import "./App.css";
const animals = [
{ id: 1, species: "Bear", habitat: "Mountains" },
{ id: 2, species: "Lion", habitat: "Sahari" },
{ id: 3, species: "Hippo", habitat: "Sahari" },
{ id: 4, species: "Eagle", habitat: "Trees" },
{ id: 5, species: "Fish", habitat: "River" },
{ id: 6, species: "Snake", habitat: "Desert" },
{ id: 7, species: "Alligator", habitat: "Everglades" },
];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: animals
}
this.onDismiss = this.onDismiss.bind(this);
}
onDismiss(id) {
const isNotID = animal => animal.id !== id;
const updatedList = this.state.animals.filter(isNotID);
this.setState({animals: updatedList});
console.log(this.state.animals)
}
render() {
return(
<div className="App">
{
animals.map((animal)=> {
return (
<div key={animal.id}>
<div>{animal.species}</div>
<div>{animal.habitat}</div>
<span>
<button onClick={()=>this.onDismiss(animal.id)}>Dismiss</button>
</span>
</div>
)
})
}
</div>
);
}
}
export default App;
I want the item to be deleted once i press the dismiss button. And bring back the updated list which will be brought about from the setState
Your render method is using animals (your initial data) instead of this.state.animals.

Categories

Resources