I am developing an angular5 application. I have an array containg list of question and I displayed it by iterating using ngFor.User can select questions of his choice by pressing ctrl key. After selecting a question by pressing ctrl key that will shown as selected (I implemented that by adding that question to an array and check at the time of iteration that perticular question is in selectedQuestions array.If that is present in that array I addedan 'active' class to display it as selected).Now I want to remove this class at the time when the user dragged the mouse to drag and drop questions to reorder it(I am using ng2-dragula for drag and drop). I have tried this following code
import {Component, OnInit, ViewChild} from '#angular/core';
export class SummaryComponent implements OnInit {
#ViewChild("myLabel") lab;
addThisQuestionToArray(person: any, i: number, event) {
if (!event.ctrlKey) {
this.selectedQuestions = [];
}
this.toggleItemInArr(this.selectedQuestions, person);
}
toggleItemInArr(arr, item) {
const index = arr.indexOf(item);
index === - 1 ? arr.push(item) : arr.splice(index, 1);
}
isQuestionSelected(question: any) {
return (this.selectedQuestions.indexOf(question) !== -1);
}
constructor(private dragula: DragulaService){
}
ngOnInit() {
this.dragula
.drag
.subscribe(value => {
this.dragging =true;
console.log("dragging");
this.lab.nativeElement.classList.remove("active");
});
}
}
HTML code summarycomponent.html is
<li class="well dragbox" *ngFor="let question of questions; let i = index" [attr.data-id]="question.QuestionId" question.firstName= "i" [attr.data-index]="i" (click)="addThisQuestionToArray(question,i, $event)" [class.active]="isQuestionSelected(question)" #myLabel > {{i}} {{question.QuestionId}} {{question.Question}}</li>
You can control element's class with ngClass, and create a conditional statement, so if you create a variable locally like dragging, and have a class you want to conditionally apply like active
<li class="well" [ngClass]="{'active': dragging}">
alternatively
<li class="well" [ngClass]=" dragging ? 'active': '' ">
Related
I'm learning Angular, and I'm working on a project ,in which, I need to use a CSS grid layout. However, I'm trying to find a way to insert a component inside a grid with given grid-area.
I tried to do this, <app-slots></app-slots>, in app.component.html but the component <app-slots> was counted as one grid place only; even though, it's 42 places.
slots.component.html:
<div class="abc" *ngFor="let in of getArrayOfNumbers(42) ;let i = index" [style.grid-row] = "i+1" style = "height:20px" > {{in}} </div>
slots.component.ts:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-slots',
templateUrl: './slots.component.html',
styleUrls: ['../../app.component.css']
})
export class SlotsComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
getArrayOfNumbers(x: number){
var slots:number[] = [];
var a: number = x;
while(x != 0){
slots.push(x);
x--;
}
return slots;
}
}
Note: If something is not clear please tell me to add more info
can you just insert the component between your tags (instead of {{in}}), then send whatever updating variables from the .ts file through that using angular's binding feature ?
two way binding
Hello guys I currently have a buttons like category. I want that when I click a button it will have a color, and when I click it again it will turn to it's original color which is white. When I click 2 button both will have dark color, then click again to remove single color.
this is my div when I'm adding a the category id
<div className={classes.scrollMenu}>
{categories.map((category) => {
return (
<>
<Button
key={category._id}
className={classes.button}
onClick={(e) => {
let values = {
price: [],
category: [category._id],
}
}}
>
{category.name}
</Button>
</>
)
})}
</div>
This is the image that when I click single button it will color one button.
Thank you
code Solution: https://codesandbox.io/s/stoic-meadow-y5cei?file=/src/App.js
App.js
import "./styles.css";
import React, { useState } from "react";
export default function App() {
let categories = ["one", "two", "three"];
const [activeFilter, setActiveFilter] = useState(["one"]);
const categoryOnClick = (category) => {
activeFilter.includes(category)
? removeCategory(category)
: setCategory(category);
};
const setCategory = (category) => {
setActiveFilter([...activeFilter, category]);
};
const removeCategory = (category) => {
const index = activeFilter.findIndex((cat) => cat === category);
activeFilter.splice(index, 1);
setActiveFilter([...activeFilter]);
};
return (
<div className="chip-list my-3">
{categories.map((category, index) => {
return (
<button
key={index}
className={`${activeFilter.includes(category) ? "active" : ""}`}
onClick={() => categoryOnClick(category)}
>
<span>{category}</span>
</button>
);
})}
</div>
);
}
css
.active {
background-color: black;
color: white;
}
check if this solution works for you
used useState hook to hold the state of buttons which you will select
.active class will apply to the button which is selected
On click of that button we will check if the button is already selected or not if selected removeCategory() function run
or if button is not selected then setCategory() function will run and it will update the state
if you need clarification please let me know thanks
Few tips to start with:
Fragment is unnecessary when wrapping single DOM element
Inline function initialisation inside a render is a bad thing. On each new re-render, it allocates extra client memory to newly initialised function. That means, for every map object you will have that many functions, that gets newly created and referenced on each reload
You can easily go with single line return statement of arrow function here. () => <hi> instead of () => { return <hi> }
As for solutions, there are quite a few ways to change button colour during execution. I will suggest the most simple (in my opinion) way to do it. Just have classname variable, then add subclass that will style button accordingly.
Example:
By default it has class name of .button, after click you simply add styling and it ends up having .button .button--red, all is left to do, declaration in css.
.button {
style button here
. . .
add additional stylings here
. . .
&.button--red { color: red }
}
As for how handler should look like, if that is what you asking. Button could be used in your new component let's say, named StyledButton or ColourfulButton that will have internal state to handle what kind of colour is represented.
I'm making a slider block and I want to create a slide block for each image I choose.
I already have a fully functioning slide block.
The question is, how can I create call the slide block from the slider block? I think there must be a way through the API and I found the function createBlock() but nothing is really working
const { createBlock } = wp.blocks;
//
// some code
//
<div id={ listId } className={ classes } key={ index }>
{createBlock('illmatic6514/slide')}
</div>
I'm expecting a slide block to be created. (To make it simple I removed variables from the slide block and put in a static image)
I'm getting "Cannot read property 'attributes' of undefined"
Even if I call createBlock('core/paragraph') I get "Objects are not valid as a React child"
You probably want to define Slide as a component instead of a block:
function Slide(props) {
return <div>{props.slideName}</div>;
}
Or as a class that extends Component:
const { Component } = wp.element
class Slide extends Component {
render() {
return (
<div>{ this.props.slideName }</div>
)
}
}
And then in your Slider block you would use that component:
edit(props) {
return (
<div>
<Slide slideName="Slide 1" />
<Slide slideName="Slide 2" />
</div>
)
}
https://reactjs.org/docs/components-and-props.html
I am just diving into ReactJS so I am quite a newbie in this Reactjs world. I have read the FB documentations and some tutorials on the internet and started my test project.
In my test project I am trying to include a progress bar for users to see their progress of filling down some forms across 3 pages. This part works all great till I wanted to add some transition magic to the process bar.
I've written the code below and I thought it would be the right way to archive my goal by pushing a prop from the parent to this child progressBar component for determining the percentage of the progress bar.
In my constructor I set the default width at 0 to update it by componentDidMount to a percentage which comes from the parent. I've managed to receive and set te style but the transition isn't working at all. I try to archive a fancy progress bar which runs from 0% width to the given width in percentage via the props.
My code look likes as follow:
ProgressBar component
import './style.scss';
import React from 'react';
import classnames from 'classnames';
class ProgressBar extends React.Component {
constructor(props) {
super(props);
this.state = { progressionStyle : { } }
}
componentDidMount() {
this.setState({
progressionStyle : {
width : this.props.progression,
transition : 'all 1500ms ease'
},
scene1 : (this.props.scene1 == 'active') ? 'active' : (this.props.scene1 == 'done') ? 'done' : '',
scene2 : (this.props.scene2 == 'active') ? 'active' : (this.props.scene2 == 'done') ? 'done' : '',
scene3 : (this.props.scene3 == 'active') ? 'active' : (this.props.scene3 == 'done') ? 'done' : '',
});
}
/**
*
* Render
* #return {JSX}
*/
render() {
return (
<div className="progress-bar">
<div className="progress-bar__inner">
<div className="progress-bar__progress">
<div className={classnames('progress-bar__progress-fill', this.props.active)} style={this.state.progressionStyle}></div>
</div>
<div id="scene1" className="progress-bar__element">
<i className={classnames('progress-bar__icon', this.state.scene1)}></i>
<span className="progress-bar__label">Scene 1</span>
</div>
<div id="scene2" className="progress-bar__element">
<i className={classnames('progress-bar__icon', this.state.scene2)}></i>
<span className="progress-bar__label">Scene 2</span>
</div>
<div id="scene3" className="progress-bar__element">
<i className={classnames('progress-bar__icon', this.state.scene3)}></i>
<span className="progress-bar__label">Scene 3</span>
</div>
</div>
</div>
);
}
}
export default ProgressBar;
You cannot set the nested state directly, you should be doing it like
componentDidMount() {
var style = {...this.state.style}
style.width = this.props.progression
style.transition = 'all 500ms ease-in'
this.setState({style});
}
Also, you need to update your state in the componentWillReceiveProps function as you are updating state based on the props.
componentWillReceiveProps(nextProps) {
var style = {...this.state.style}
style.width = nextProps.progression
style.transition = 'all 500ms ease-in'
this.setState({style});
}
To make this effect work, I've found out the solution was to wrap the style into a function and call via request animation frame via as fol
componentDidMount() {
requestAnimationFrame(()=> {
this.showProgress();
});
}
showProgress() {
var style = { };
style.width = this.props.progression;
style.transition = 'all 1500ms ease-in';
this.setState({style});
}
https://stackoverflow.com/a/43779273/968898
Currently upgrading from a jquery / php webapp to react. All is going well and I understand the concepts behind react etc. The only issue I can't find a workaround is how to dynamically add / delete a class based on where the user clicks. I need this because I have a few dropdowns which trigger when the user click it and need to be hidden if they click somewhere else.
From: Give a class of "selected" when clicked on another <a> then remove the class if it's the same <a>
I've taken this example as it is simple, Jquery solution to the problem:
var h2 = $("h2 a");
h2.on("click", function() {
if ($(this).is(".selected")) {
$(this).removeClass("selected");
} else {
h2.removeClass("selected")
.filter(this).addClass("selected")
}
});
How to mimic the same functionality in react (and / or redux)?
Image to further clarify
The thing is, you want to toggle some data on click event and change the classname of a html element accordingly.
Your data that 'selected' class based on could come from anywhere, from parent or component state. You would do something like this :
<div className={ myData ? 'selected' : '' } ></div>
But there is a better way to display classname changes with a library called classnames. The same thing is accomplished as :
<div className={ classNames({ 'selected' : myData }) } ></div>
Until now, we have seen how to display changes on render function. Second thing you need is to listen to click events and fire the function that will eventually toggle the data that controls the 'selected' classname, in my example 'myData'.
Here is a working example, there might be various ways to accomplish this. But I strongly recommend using classnames library to toggle classnames.
The workaround about removing class when another element ( apart from li elements we observe ) clicked could be solved by a click event listener.
For instance :
import React, { Component } from 'react'
import classNames from 'classnames'
class DropDown extends Component {
constructor(props){
super(props)
this.state = {
activeSelected : ''
}
this.handleClick = this.handleClick.bind(this)
}
componentDidMount(){
global.document.addEventListener( 'click', this.handleClick, false )
}
componentWillUnmount(){
global.document.removeEventListener( 'click', this.handleClick, false )
}
handleClick(event){
if( event.target.className.includes('not-changing-css-class') &&
this.state.activeSelected !== ''
) this.setState( { activeSelected : '' } )
}
render(){
let { activeSelected } = this.state
return (
<ul>
<li
className={ classNames({
'not-changing-css-class' : true,
'selected' : activeSelected === 'item1'
}) }
onClick={ event => this.setState({ activeSelected : activeSelected === 'item1' ? '' : 'item1' }) }
>
Item 1
</li>
<li
className={ classNames({
'not-changing-css-class' : true,
'selected' : activeSelected === 'item2'
}) }
onClick={ event => this.setState({ activeSelected : activeSelected === 'item2' ? '' : 'item2' }) }
>
Item 2
</li>
<li
className={ classNames({
'not-changing-css-class' : true,
'selected' : activeSelected === 'item3'
}) }
onClick={ event => this.setState({ activeSelected : activeSelected === 'item3' ? '' : 'item3' }) }
>
Item 3
</li>
</ul>
)
}
}
You can hold the selected element index (or ID if you use IDs) in the component state. You can use redux store if you think this state will be relevant to any other component in your app, but starting with state is simpler.
Once you have this state. You can check within your render() function whether a link is selected or not, by comparing with the component state. You would also update the selectedIndex whent the links are clicked.
A simple example to render the links could be as follows. Note that you can extract parts of these to be functions instead of using expressions in JSX.
```
allLinks.map( (link, index) =>
<a href={link.target} className={this.state.selectedIndex === index ? 'selected' : null}/>
)
```