2

enter image description here

--> DEMO CODE <--

I'm trying to make when the word is found the word inside the TIP popup is crossed out.

Code when is word is found

  verifyFindWord = (words) => {
for (let word of words) {
  let lettersSelected = this.getLetterSelectedSameWord(word);

  if (lettersSelected == word.length) {
    alert("You find the word: " + word);
  }
}

};

I created this css code and it shows all the crossed out words, and the idea is if the word is found this word should be crossed out automatically.

<div className="words">
                  {words.map((word, index) => (
                    <span
                      key={word + index}
                      className={word ? "finded" : ""}
                    >
                      {word}
                      <br />
                    </span>
                  ))}
                </div>
André
  • 338
  • 3
  • 15

3 Answers3

1

In the <span> tag the className value must consider the existence of word in a list of found words. For example, with findedWords.includes(word):

<div className="words">
    { words.map((word, index) => (
        <span key={word + index}
              className={this.state.findedWords.includes(word) ? "finded" : ""}>
            {word}<br />
        </span>
    ))}
</div>

So, in the verifyFindWord function you pre-populate the findedWords list:

verifyFindWord = words => {
    for (let word of words) {
        let lettersSelected =
            this.getLetterSelectedSameWord(word);

        if (lettersSelected == word.length) {
            alert("You find the word: " + word);
            const findedWords = this.state.findedWords;
            findedWords.push(word);
            this.setState({ findedWords });
        }
    }
}
Sergio Cabral
  • 6,490
  • 2
  • 35
  • 37
0

i think you need to use a state object and add a key/value:

const [isCrossed, setIsCrossed] = useState({isCrossed : false }) // init state

If the word is found, then add a conditional class on your tag <tag className={ isCrossed ? "crossed" : "uncrossed"}>{word}</tag> to diplay

rachOS
  • 93
  • 1
  • 7
  • I need to remind you that I am using Class Components and useState would not work in this case, but if you want to refactor this code to Functional components I would appreciate it. But I believe that using state and constructor this is not possible. – André Jun 10 '21 at 13:24
  • 1
    Its possible but a little more tedious. I take a look soon ;) – rachOS Jun 10 '21 at 13:52
0

Instead of:

words: ["Rectang", "Circle", "Donut", "A", "Arc", "EL", "Elipses", "DO"],

I'll use a:

words: ["Rectang", "Circle", "Donut", "A", "Arc", "EL", "Elipses", "DO"].map(word => ({found: false, word})),

so each word has a status found that you'll have to update when a word is found and which you can use to crossed out the words. Something like:

  if (lettersSelected == word.length) {
    alert("You find the word: " + word);
    state.words = state.words.map(w => (w.word === word ? { word, found: true} : w)); 
  }

And in your html:

{words.map((word, index) => (
    <span
       key={word.word + index}
       className={word.found ? "finded" : ""}
    >
       {word.word}
       <br />
    </span>
 ))}

Your code fixed:

import React, { Component } from "react";
import { Board } from "../../components/Board";
import "./styles.css";
import OverlayTrigger from "react-bootstrap/OverlayTrigger";
import Popover from "react-bootstrap/Popover";
import Button from "react-bootstrap/Button";
//import getWords from '../../utils/words';

import { createGame } from "hunting-words";

const options = {
  wordsCross: false,
  inverseWord: false,
  wordInVertical: true,
  wordInHorizontal: true,
  wordDiagonalLeft: false,
  wordDiagonalRight: false
};

export default class Easy extends Component {
  state = {
    columns: 16,
    rows: 16,
    game: new createGame(0, 0, []),
    words: ["Rectang", "Circle", "Donut", "A", "Arc", "EL", "Elipses", "DO"].map(word => ({found: false, word})),
  };

  constructor(props) {
    super(props);
  }

  componentDidMount() {
    const { rows, columns, words } = this.state;
    this.setState({
      game: new createGame(rows, columns, words, options)
    });
  }

  getLetterSelectedSameWord = (word) => {
    let lettersSelected = 0;
    this.state.game.board.filter((row) => {
      lettersSelected =
        lettersSelected +
        row.filter((el) => {
          return el.word === word && el.isSelected;
        }).length;
    });

    return lettersSelected;
  };

  verifyFindWord = (words) => {
    for (let word of words) {
      let lettersSelected = this.getLetterSelectedSameWord(word.word);

      if (lettersSelected === word.word.length) {
        alert("You find the word: " + word.word);
        this.setState({words: this.state.words.map(w => (w.word === word.word ? { word, found: true} : w))}); 
      }
    }
  };

  selectLetter = (item) => {
    let game = this.state.game;

    game.board[item.row][item.column].setIsSelected(!item.isSelected);

    this.setState({
      game: game
    });
    this.verifyFindWord(item.word);
  };
  wordsText = () => {};
  render() {
    const { rows, columns, board, words } = this.state.game;

    return (
      <div>
        <div className="easy-container">
          <h1>Hunting-Words</h1>

          <Board board={board} selectLetter={this.selectLetter.bind(this)} />
          {["top"].map((placement) => (
            <OverlayTrigger
              trigger="click"
              key={placement}
              placement={placement}
              overlay={
                <Popover id={`popover-positioned-${placement}`}>
                  <Popover.Title as="h3">{`WORDS:`}</Popover.Title>
                  <Popover.Content>
                    <div className="words">
                      {words.map((word, index) => (
                        <span
                          key={word.word + index}
                          className={word.found ? "finded" : ""}
                        >
                          {word.word}
                          <br />
                        </span>
                      ))}
                    </div>
                  </Popover.Content>
                </Popover>
              }
            >
              <Button variant="secondary">TIP</Button>
            </OverlayTrigger>
          ))}
        </div>
      </div>
    );
  }
}
Nico_
  • 1,388
  • 17
  • 31
  • code notes: when I include the .map(word => ({found: false, word})), the words do not appear on the board. Removing the information from the array the words reappear but when I find a word the alert appears and in the TIP box all the words disappear... – André Jun 10 '21 at 13:33
  • It's because your array of words (previously `["Rectang", "Circle", "Donut", "A", "Arc", "EL", "Elipses", "DO"]` is now an array of object: `[{word: "Rectang", found: false}, {word: "Circle", found: false }, {word: "Donut", found: false },...]`. That means every time you used `word`, you have to use `word.word`. – Nico_ Jun 11 '21 at 07:13
  • I updated the code and the words still don't appear on the board, and when I click on TIPS, the following error appears: Error: Objects are not valid as a React child (found: object with keys {word, found}). If you meant to render a collection of children, use an array instead. – André Jun 11 '21 at 11:28
  • I added the full code updated in my answer but as you can see it's not working because your `item` in the `selectLetter` function has a property `word` which is always an empty array so the check in `verifyFindWord` never happens. – Nico_ Jun 11 '21 at 12:31
  • It's not really working, I'll give you the developer link here if you're interested in taking a look. github.com/rogeriomattos/hunting-words-game // SAMPLE -> https://rogeriomattos.github.io/hunting-words-game/ The person who developed the code did not provide the crossed out example ... – André Jun 11 '21 at 12:56
  • 1
    Ok since the `words` are used by the function of the library when you do `createGame`, I would add a `found: []`in the state and then in `validate`, I would add: `if (!this.state.found.contains(word)) this.setState([...this.state.found, word]);`. So the `found` array contains the found words. Then you can do: `className={state.found.contains(word) ? "finded" : ""}`. Anyway it will not work since the `selectLetter` function does nothing because the `item.word` is always equal to `[]`. PS: The library you used is bugged (if you select all the letters in the example you will win). – Nico_ Jun 11 '21 at 15:25
  • I would like to thank you for your concern about my problem. This project would serve for distance learning. Do you have any suggestions for another project or any ideas on how to solve this project? – André Jun 11 '21 at 17:28
  • I think I'll do my own function to check if a word is selected, I don't think it would be that hard. You have to check if the `status` is `selected` or not and if it's in the same row/column than the 2 previous char (or the last one if there is only one char selected). You can also remove the other selected letters if the last one is not on the same row/col. Then you add that new letter to the field `word` of your item and then you only have to check if the word matches one of your defined words. – Nico_ Jun 13 '21 at 08:05
  • I don't know how I should do this could it help me? – André Jun 14 '21 at 13:31
  • No sorry I don't have the time, try on your side with small function that you can check easily and if you are stuck, ask for help in a new question here with your progress. – Nico_ Jun 15 '21 at 07:19
  • Oh no, oh no, oh no no no – André Jun 15 '21 at 11:16