sorting computed values and updating computed values vue - javascript

In my vue app, I get some JSON from my API, I am then computing that returned data and sorting it via one of it's attributes, I am then wanting to then resort it every time that attribute is updated on the client side, I thought it would be enough to add `v-model="tag.weight" to the input but apparently not? What am I doing incorrectly?
<div class="mt-6" v-if="this.sortedTags">
<div class="w-full flex justify-between pb-2 border-white">
<div class="w-1/3 p-4 font-black">Tag</div>
<div class="p-4 font-black">Active</div>
<div class="p-4 font-black">Weight</div>
</div>
<div class="w-full flex justify-between" v-for="tag in this.sortedTags" :key="tag.id">
<div class="w-1/3 p-4">{{ tag.tag }}</div>
<div class="p-4"><input type="checkbox" /></div>
<div class="p-4"><input type="text" v-model="tag.weight" size="3" class="text-black"/></div>
</div>
</div>
computed: {
...mapState(['admin']),
sortedTags() {
return this.admin.tags.sort(function(a, b) {
a.weight - b.weight;
});
}
}
What I was hoping for what the 1) if entered a number into the weight field that is bound tag.weight it would order it based on that input, and 2) When I add new object to the data, it would resort it.

I got similar result when omitting the return, it will give you response, but re-sorting won't work.
Therefore, just use return a.weight - b.weight; instead of a simple a.weight - b.weight;
Detailed explanation : https://stackoverflow.com/a/38159151/3256489

Related

A select component in a wrapper component does not change its placeholder but value changes

I have a select component that doesn't change it's placeholder when I'm clicking its options. It's wrapped around on another component that serves as the outline of like its title. paragraph and then the select component. I also use it on another select component and it also doesn't work. I am pretty sure it changes it value since I checked the state and also the functionality works excpect the changing of the so called placeholder. This is the original outline which works.
<div className={`flex flex-col col-span-6`}>
<div className="flex items-center mb-1">
<h2 className='text-sm'>TYPE OF FLIGHT ANF REGION</h2>
<FontAwesomeIcon icon={faGlobe} className="text-[#2B8E9B] ml-2" />
</div>
<p className='text-xs mb-3'>Choose a type of flight, either DOMESTIC or INTERNATIONAL, and pick which region your coming.</p>
<div className={`grid grid-cols-2 gap-4`}>
<FlightTypeComponent flights={domestic} flightLocalType={"domestic"} {...{flightType, locationsFilter, flightTypeClick ,regionSetter}}/>
<FlightTypeComponent flights={international} flightLocalType={"international"} {...{flightType, locationsFilter, flightTypeClick ,regionSetter}}/>
</div></div>
This is the current outline which doesn't work:
<TwoComponents title={"TYPE OF FLIGHT ANF REGION"} icon={faGlobe} colSpan={"col-span-6"} childrenCss={"grid-cols-2"} paragraph={"Choose a type of flight, either DOMESTIC or INTERNATIONAL, and pick which region your coming."}>
<FlightTypeComponent flights={domestic} flightLocalType={"domestic"} {...{flightType, locationsFilter, flightTypeClick ,regionSetter}}/>
<FlightTypeComponent flights={international} flightLocalType={"international"} {...{flightType, locationsFilter, flightTypeClick ,regionSetter}}/>
</TwoComponents>
The wrapper in question. I both included both components even if I only showcased the TwoComponents incase of any errors or bad practices.
const EachComponentOutline = () => {
const TwoComponents = ({children, title, paragraph, icon, colSpan, childrenCss}) => {
return (
<div className={`flex flex-col ${colSpan}`}>
<div className="flex items-center mb-1">
<h2 className='text-sm'>{title}</h2>
<FontAwesomeIcon icon={icon} className="text-[#2B8E9B] ml-2" />
</div>
<p className='text-xs mb-3'>{paragraph}</p>
<div className={`grid ${childrenCss} gap-4`}>
{children}
</div>
</div>
)}
const OneComponent = ({children, title, icon, paragraph, colSpan}) =>
(
<div className={`flex flex-col ${colSpan}`}>
{icon ? (
<div className="flex mb-1">
<h2 className='text-sm'>{title}</h2>
<FontAwesomeIcon icon={icon} className="text-[#2B8E9B] ml-2" />
</div>
)
: (<h2 className='text-sm mb-1'>{title}</h2>)
}
<p className="text-xs mb-3">{paragraph}</p>
{children}
</div>
)
return {TwoComponents, OneComponent}
}
picture of the placeholder since I'm not sure if "placeholder" is the right term
I answered it but I don't know why and I hope someone can better explain it. Instead of trying to create two components on a single function. You create each component in its own separate function so basically like removing the overall parent function for both TwoComponent and OneComponent. I think using a custom hook would return data and not a whole component so it's better to export and import it.

How to fix error objects are not valid react child?

I am trying map through an object with the goal to render the key and their value inside a p tag. I am having the error message object are not valid react child.
How can I overcome this error?
<div className="d-flex flex-wrap">
{
Object.keys(features).map((item,index) => {
console.log('type',item);
console.log(features[item]);
return <p key={item} className="fw-bold bg-light fs-6 text-primary m-1 p-2">{{[item]:features[item]}}</p>
})
}
</div>
This error is because the code
{{[item]:features[item]}}
actually results to an object. So child of <p> tag is an object. You can solve it by using Template literals inside <p> tag
<div className="d-flex flex-wrap">
{
Object.keys(features).map((item,index) => {
console.log({[item]:features[item]});
console.log(features[item]);
return <p key={item} className="fw-bold bg-light fs-6 text-primary m-1 p-2" >{`{${item}: ${features[item]}}`}</p>
})
}
</div>
In this section of React doc, it is said that:
You can put any valid JavaScript expression inside the curly braces in JSX
Moreover {[item]:features[item]} itself is not a valid expression, according to this list
So instead, you have to embed 2 expressions, item and features[item]
return (
<p key={item} className="fw-bold bg-light fs-6 text-primary m-1 p-2">
{item}: {features[item]}
</p>
)
It is because of the double brackets in your code
Use only one brackets like this
{[item]:features[item]}
Following is JSON
{[item]:features[item]}
If you meant to render the JSON as a string then do like this.
JSON.stringify({[item]:features[item]})
Do it like this
Object.keys(features).map((item) => {
return <p> {item} : {features[item]}</p>
}

Random background color on vuejs loop

A little help here, I'm stuck. I don't know even how to start.
I have this v-for for printing my "contracts".
I'm still not to submerged on vuejs workflow so I'm not being able to work around this.
How can I give a diferent background-color to every col div there? But not randomly, I want for them to keep the color even if the page is reloaded, my aproach was using the id of my contract and doing something with that but I don't understand much about vuejs to know how to do it.
Let's say I want to make a javascript function to give a class depending on the contractType.id, how do I execute that function with each loop? Is there a proper way to do this on vuejs?
<template>
<div class="row" v-if="contractTypes && contractTypes.length > 0">
<div class="col-md-4 c-button" v-for="(contractType, index) in contractTypes" :key="index" #click="choose($event.srcElement.innerHTML, index, contractType.id)">
<div class="col p-4 d-flex flex-column position-static text-center">
<strong class="d-inline-block mb-2 text-primary">World</strong>
<h3 class="mb-0">{{ translations && translations[contractType.id] ? translations[contractType.id].usecasetitle : contractType.usecasetitle }}</h3>
<p class="card-text mb-auto">{{ translations && translations[contractType.id] ? translations[contractType.id].description : contractType.title }}</p>
<button class="btn btn-primary">Click</button>
</div>
</div>
</div>
<div v-else>
<h1>Leider stehen für Sie derzeit keine Verträge zur Auswahl.</h1>
</div>
</template>
If you want custom styles on the different contract types, you can d a method:
/*
* #param {string} contract -- a foo bar
* #return {object} -- Bunch of boolean controlled classes
*/
getContractClasses (contract)
{
return {
'style1': contract === 'a string',
'style2': contract === 'another thing',
'style3': true, // This one is always going to be on and will have a bunch of shared styles between all of them
}
},
Then, in the template,
<h3 :class="getContractClasses(contract)">
Finally, just do the different styles in the style guide in the component housing the v-for.
Also, might I suggest an unwritten rule of sorts to remove all the logic from the template layer, and have that as a method or computed? Reading that long ternary inline is a big "No thank you", from me.

Returning a div x amount of times ReactJS

I need to return the following code in ReactJS x amount of times. I am trying to populate a card with names based on how many people there are in a team.
So if x was 5, I would need that to appear 5 times.
<div className="row align-items-center justify-content-center m-b-10">
<h5>Name goes here</h5>
</div>
This is the type of object I'm dealing with:
Is there a clean way of doing this?
First, it depends on how your data is defined, for example, if the names are in an array, you can create an array of JSX elements that contain each , you can use .map()
Just use:
const x = 5
Array(x).fill().map((el, index) =>
<div className="row align-items-center justify-content-center m-b-10" key={index}>
<h5>Name here</h5>
</div>
)
This is not ideal because you can also iterate over the array of names itself, and get the same result, even cleaner.
<div>
{
arrayOfNames.map((el, index) => (
<div className="row align-items-center justify-content-center m-b-10" key={index}>
<h5>`${el.first_name} ${el.last_name}`</h5>
</div>
))
}
</div>
Assuming you got all of the people names in an array. You can use map over the array when rendering`:
{ yourObject.map((person, idx)=>(
<div className="row align-items-center justify-content-center m-b-10" key={idx}>
<h5>{person.first_name + " " + person.last_name}</h5>
</div>
)}
(Of course, make sure this code is wrapped with another element)

How can I dynamically render both javascript data and html within the same angular curly braces ({{ }})?

I am rendering different kinds of attributes within the same html element in the following manner:
Javascript:
var dataAttribute = {
value:function(){ return 1;}
}
var listAttribute = {
value:function(){ return "<div>My Arbitrary HTML
<div>1</div>
<div>2</div>
<div>3</div>
</div>";}
}
var attributes = [dataAttribute,listAttribute]
HTML:
<div ng-repeat="attribute in attributes"> {{ attribute.value() }} </div>
How do I get the html in the listAttribute to render as HTML and not as text, while still retaining the ability to render the normal data of the dataAttribute?
You just should not. Use ng-switch directive if you want to render different things based on properties of items in your collection. ( in worst case use series of ng-if inside your ng-repeat)
Do not invent another templating engine if you already using angular, you are just confusing yourself.
Little more explanation here. You already have code that generates that html somewhere. It really better by angular directives.
<div ng-repeat="attribute in attributes" ng-switch="attribute.type">
<div ng-switch-default> {{ attribute.value() }} </div>
<div ng-switch-when="table"><my-table data='attribute.value()'></my-table></div>
<div ng-switch-when="list"><my-list data='attribute.value()'></my-list></div>
</div>
And set of directives
.directive('myTable', myTable).directive('myList', myList)
will hold all the logic to produce html from the data.
I.E. don't mix layout and data in one structure.
The solution was a combination of #vittore and #YOU's answers:
Javascript:
var dataAttribute = {
value:function(){ return 1;},
type:'data'
}
var listAttribute = {
value:function(){ return "<list-directive></list-directive>";},
type:'list'
}
var attributes = [dataAttribute,listAttribute]
HTML:
<div ng-repeat="attribute in attributes" ng-switch="attribute.type">
<div ng-switch-default> {{ attribute.value() }} </div>
<div ng-switch-when="list" ng-bind-html="attribute.value()"></div>
</div>
Thanks!

Categories