7

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>
    );
  }
}
Wasteland
  • 4,889
  • 14
  • 45
  • 91

5 Answers5

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)
    }
});
Andreyco
  • 22,476
  • 5
  • 61
  • 65
  • 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.) – Wasteland Mar 13 '16 at 21:51
  • Edited my response. Added code that extracts unique tag names. – Andreyco Mar 13 '16 at 22:05
  • 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 – Wasteland Mar 19 '16 at 14:58
  • 1
    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) – Andreyco Mar 19 '16 at 17:15
  • Ok, I see. Thank you. – Wasteland Mar 19 '16 at 17:59
  • I'm getting an error: I did (image, image.id) => blah blah key={image.id} blah. It does not seem to like the first image.id – Wasteland Mar 19 '16 at 18:17
  • 1
    `_.map(this.props.images, (image) => )` – Andreyco Mar 19 '16 at 20:10
  • Brilliant use of the map. Thanks for updating this. – JamMan9 Feb 21 '19 at 10:42
3

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);
});
andromeda
  • 4,433
  • 5
  • 32
  • 42
2

Typescript sets source

For those who are using Typescripts I would recomend TypeScript Set

Array.from(new Set(yourArray.map((item: any) => item.id)))
Peppe426
  • 99
  • 6
0

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

Rafael Grillo
  • 232
  • 2
  • 8
  • Will not work, since each object in collection (array) is different object (references are different). – Andreyco Mar 13 '16 at 21:48
  • But he want only the 'tag' value of each elements to build a menu. He can create a set with each tag string. No? – Rafael Grillo Mar 13 '16 at 21:50
  • 1
    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 :) – Andreyco Mar 13 '16 at 22:26
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

Senthuran
  • 1,583
  • 2
  • 15
  • 19