0

In a React project, I want to dynamically access an object property name using a string variable I pass through props. I am able to pass a value as string; however, when I try to use it to access the object property it doesn't work.

Here's an example:

const passedField = 'title'; // this comes from props
const book = { title: 'Sample title', content : 'some content' };
book.passedField; // returns undefined

I access title like this book.title

I want to access it like book.passedField but I get undefined on console.

How can I achieve this?

AnonymousSB
  • 3,516
  • 10
  • 28
user1661286
  • 133
  • 1
  • 3
  • 12
  • Are you passing `passedField` as a props from another component? – SakoBu Dec 19 '18 at 01:35
  • book[passedField] should do it. In Javascript, object properties can be accessed by name: https://stackoverflow.com/questions/4255472/javascript-object-access-variable-property-by-name-as-string – Yacine Filali Dec 19 '18 at 01:42
  • yes passing the passedField as a prop from another component, it works and proper value is being passed. I need 'build' a new return depending on the value that's passed , like this `const passedField = this.props.passedField; const filterText = this.props.filterText.toLowerCase(); return ( book.passedField.indexOf(filterText) >= 0 );` so the return would be either `book.title.toLowerCase().indexOf(filterText)` or `book.content.indexOf(filterText)` depending on the value – user1661286 Dec 19 '18 at 02:14

3 Answers3

4

book.passedField will be returning undefined because there is no passedField in book. Instead use bracket notation as below

const book = { title: 'abc', pages: 350 };
const passedField = 'pages';

console.log(book[passedField])
Isaac
  • 12,042
  • 16
  • 52
  • 116
  • I don't want to access that property, I need to build it . passedField is a sting, either title or content, based on that I need to access that property like . book.title or book.content – user1661286 Dec 19 '18 at 02:38
  • @user1661286: passedField is a string. it's with value 'pages' or 'title'. Please at least play or understand with my code. – Isaac Dec 19 '18 at 02:53
3

What you're using is called a dot notation property accessor. What you need to use is a bracket notation property accessor.

book.title and book['title'] are the same, which means you can assign title to a variable, and use the variable name instead like this.

const passedField = 'title';
book[passedField]; // same as book['title']

You might only be familiar with bracket notation with Arrays, like myArray[0], but they work with Objects too! (because Arrays in JavaScript are actually objects)

Solution

const books = [
  {
    title: 'The Art of War',
    contents: 'An ancient Chinese military treatise dating from the Spring and Autumn Period'
  },
  {
    title: 'Winnie the Pooh',
    contents: 'Pooh is naive and slow-witted, but he is also friendly, thoughtful, and steadfast.'
  }
]

class Book extends React.Component {
  constructor(props) {
    super(props);
    this.findBookByFilter = this.findBookByFilter.bind(this);
  }
  
  findBookByFilter() {
    let result = null
    if (books) {
      const {passedFilterField, filterText} = this.props;
      
      result = books.filter(book => {
        return book[passedFilterField].toLowerCase().includes(filterText.toLowerCase());
      }).map(book => <p>{book.title}</p>)
    }
    return result;
  }
  
  render () {
    return this.findBookByFilter();
  }
}

class App extends React.Component {
  render() {
    return (
      <Book
        passedFilterField='contents' 
        filterText='thoughtful'
      />
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Notes

  • I moved your {book && book.filter} logic to a function called findBookByFilter
  • I used includes instead of indexOf in the filter
  • I used destructuring assignment for this.props
  • I return the matched title, rather than <Link /> for demo purposes.

Documentation

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_accessors

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

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment

AnonymousSB
  • 3,516
  • 10
  • 28
  • thanks yes passing the passedField as a prop from another component, it works and proper value is being passed. I need 'build' a new return depending on the value that's passed , like this `const passedField = this.props.passedField; const filterText = this.props.filterText.toLowerCase(); return ( book.passedField.indexOf(filterText) >= 0 );` so the return would be either `book.title.toLowerCase().indexOf(filterText)` or `book.content.indexOf(filterText)` depending on the value – user1661286 Dec 19 '18 at 02:14
  • @user1661286 Can you update your question with what `passedField` is supposed to be? What is the function wrapping the code you provided in this comment? – AnonymousSB Dec 19 '18 at 02:24
  • `{books && books .filter(book => { const passedFilterField = this.props.passedFilterField; const filterText = this.props.filterText.toLowerCase(); return book.title.toLowerCase().indexOf(filterText) >= 0; }) .map(book => { return ( ); })}` – user1661286 Dec 19 '18 at 02:27
1

You can access object properties using book[passedField]

francium
  • 2,384
  • 3
  • 20
  • 29
  • I don't want to access that property, I need to build it . passedField is a sting, either title or content, based on that I need to access that property like . book.title or book.content – user1661286 Dec 19 '18 at 02:38
  • Either way, that `passedField` variable contains the string ('title' or 'content'). Using the `book[passedField]` will give you access to the `book.title` or `book.content` properties. If I'm understanding you're wording correctly, you're only trying to read that property (either title or content). Then this answer, as other users have pointed out as well, is in fact correct. If you're doing something else, you need to be more clear (especially when you say 'build'). – francium Dec 19 '18 at 05:19