8

I'm a beginner in JavaScript and an even bigger beginner in ReactJS. Most of the following I've taken from tutorials and am trying to adapt it. So the codes displays all the values from the "tag" (people, places, places, etc.). It displays it as inline li elements as it's going to be a menu. The problem is that it displays all the tag for all the elements. I just want it to catch the unique 'tag' values for the menu (eg. people, places, things,...). I've tried _.uniq but it did not display the array. Thank you.

import React from "react";
import GalleryHeader from './GalleryHeader';
import ImageEntry from './ImageEntry';
import _ from 'lodash';

export default class GalleryImages extends React.Component {

    renderItems() {
        return _.map(this.props.images, (image, index) => <ImageEntry key={index} {...image} />);
    }

  renderMenu() {
    return _.map(this.props.images, (image, index) => <GalleryHeader key={index} {...image} />);
  }


  render() {

    return (
      <div>
      <ul class="list-inline">
        {this.renderMenu()}
      </ul>
        {this.renderItems()}          
      </div>
    );
  }
}

GalleryHeader

import React from "react";


export default class GalleryHeader extends React.Component {

  render() {

    return (
            <li>{this.props.tag}</li>
    );
  }
}

Images are stored in:

Gallery

import React from "react";

import GalleryImages from './Gallery/GalleryImages';


var images = [{
  "id": 1,
  "tag": "people",
  "src": "img/img1.jpg",
  "bsrc": "img/img1b.jpg",
  "alt": "Some description"
}, {
  "id": 2,
  "tag": "places",
  "src": "img/img2.jpg",
  "bsrc": "img/img2b.jpg",
  "alt": "Some description"
}, {
  "id": 3,
  "tag": "places",
  "src": "img/img3.jpg",
  "bsrc": "img/img3b.jpg",
  "alt": "Some place description"
}, {
  "id": 4,
  "tag": "things",
  "src": "img/img4.jpg",
  "bsrc": "img/img4b.jpg",
  "alt": "Internet of things"
}, {
  "id": 5,
  "tag": "people",
  "src": "img/img5.jpg",
  "bsrc": "img/img5b.jpg",
  "alt": "A personal person"
}, {
  "id": 6,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 7,
  "tag": "people",
  "src": "img/img7.jpg",
  "bsrc": "img/img7b.jpg",
  "alt": "Tarabaora"
}, {
  "id": 8,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 9,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}];

export default class Gallery extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      images,
      people: _.filter(images, {tag: "things"}),    // or in ES6 just people
      sources: _.filter(images, {tag: "src"}),
      places: _.filter(images, {tag: "places"}),
      cats: _.uniq(images)
    };
  }

  render() {
    // This is how you can filter them
    var ima = _.filter(images, {tag: "things"});
    console.log(ima);


    return (
      <div className="koko">
        <h1>This isGalleryfemCount</h1>
        <GalleryImages images={this.state.images} />
      </div>
    );
  }
}

5 Answers 5

12

As I understand, you want to filter out original image collection by given tag. Correct?
If so, create filter function, which accepts tag and collection to filter. You can reuse this function then.

var images = [{
  "id": 1,
  "tag": "people",
  "src": "img/img1.jpg",
  "bsrc": "img/img1b.jpg",
  "alt": "Some description"
}, {
  "id": 2,
  "tag": "places",
  "src": "img/img2.jpg",
  "bsrc": "img/img2b.jpg",
  "alt": "Some description"
}, {
  "id": 3,
  "tag": "places",
  "src": "img/img3.jpg",
  "bsrc": "img/img3b.jpg",
  "alt": "Some place description"
}, {
  "id": 4,
  "tag": "things",
  "src": "img/img4.jpg",
  "bsrc": "img/img4b.jpg",
  "alt": "Internet of things"
}, {
  "id": 5,
  "tag": "people",
  "src": "img/img5.jpg",
  "bsrc": "img/img5b.jpg",
  "alt": "A personal person"
}, {
  "id": 6,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 7,
  "tag": "people",
  "src": "img/img7.jpg",
  "bsrc": "img/img7b.jpg",
  "alt": "Tarabaora"
}, {
  "id": 8,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}, {
  "id": 9,
  "tag": "places",
  "src": "img/img6.jpg",
  "bsrc": "img/img6b.jpg",
  "alt": "Interesting place"
}];

const filter = (tag, arr) => arr.filter(img => img.tag === tag);

// or in ES5
// var filter = function(tag, arr) {
//    return arr.filter(function(img) {
//        return img.tag === tag;
//    })
// };

const filtered = filter('people', images);

Edit
Added code to pick all unique tag names. Dependency free. Unline Set, this works in IE < 11.

const uniqueTags = [];
images.map(img => {
    if (uniqueTags.indexOf(img.tag) === -1) {
        uniqueTags.push(img.tag)
    }
});
Sign up to request clarification or add additional context in comments.

8 Comments

Thank you. You've preemptied my next question. That's exactly what I'm trying to do and your answer will come handy. At the moment, I'm stuck one step before that. Trying to generate a menu that should be: places, people, things. My code above generates: people, places, places, things, people, places, people, places, etc.)
Edited my response. Added code that extracts unique tag names.
Hi Andrey. I wonder if you could answer one more question on my code. In the renderItems function, do I need the 'index' argument in (images, index) and the subsequent "key={index}? What is the index for? It seems to work without. Thank you
Technically, you don't need it. On the other hand React asks you to provide key prop when rendering array if items for internal optimisations. Actually, it's better to avoid passing index as key, instead unique value should be passed. In your case, you may use key={image.id}, since it's unique. In situations when you cannot assign unique value, feel free to use index (when there is no better option)
_.map(this.props.images, (image) => <ImageEntry key={image.id} {...image} />)
|
4

It is similar The SQL SELECT DISTINCT Statement in javascript

const uniqueTags = [];
images.map((item) => {
  var findItem = uniqueTags.find((x) => x.tag === item.tag);
  if (!findItem) uniqueTags.push(item);
});

Comments

3

Typescript sets source

For those who are using Typescripts I would recomend TypeScript Set

Array.from(new Set(yourArray.map((item: any) => item.id)))

Comments

1

Since they are plain strings you can create a JavaScript Set for that.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set

3 Comments

Will not work, since each object in collection (array) is different object (references are different).
But he want only the 'tag' value of each elements to build a menu. He can create a set with each tag string. No?
Then yes. Unfortunately, you need flatten array (given in example) and then create Set from such array const tags = new Set(images.map(img => img.tag)); Unfortunately, we need to support old IE. Without this, I would definitely go with Set as you suggest :)
0

As stated in this documentation[1] we can use the uniqBy method to return the unique element in an object array. Please refer the below code.

import _ from 'lodash';
_.uniqBy([{ 'id': 100 }, { 'id': 200 }, { 'id': 300 },{ 'id': 100 }], 'id');

This will return an output like this [{ 'id': 100 }, { 'id': 200 }, { 'id': 300 }]

[1] https://lodash.com/docs/#uniqBy

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.