Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relation with valueField: title looses relation on update #2063

Closed
FredrikSigvartsen opened this issue Feb 4, 2019 · 19 comments
Closed

Relation with valueField: title looses relation on update #2063

FredrikSigvartsen opened this issue Feb 4, 2019 · 19 comments

Comments

@FredrikSigvartsen
Copy link

FredrikSigvartsen commented Feb 4, 2019

Describe the bug

I'm using NetlifyCMS and GatsbyJS. I'm having a problem to make it easy for the customer to make relations through other pages with the relation-widget in Netlify CMS. The problem appears when the customer is updating the title field:
- {label: "Product category", hint: "Search category name", name: "productCategory", widget: "relation", collection: "categories", searchFields: ["title"], valueField: "title", displayFields: ["title"]}

To Reproduce

  1. Map "productCategory" with markdown.frontmatter.title in gatsby-config-js.
  2. Make a Product that has a relation to a category. E.g. the product "Candybar" to category "Chocolate".
  3. Change category title from "Chocolate" to "Cocoa".
  4. Error: Then the relation between the product Candybar and Cocoa/Chocolate is lost, and then the user would need to update all products with a relation to Cocoa-category.

Expected behavior
I would expect the relation to be preserved even though the title is changed. There are multiple ways to handle this, as far as my knowledge goes:

  1. When changing the title the slug is not updated, and therefore it could be use as a valueField in the relation-widget. Is this possible? I have seen: Make sluggification visible, customizable, and fail-safe #445 , but will this include this possibility?
  2. Using a generated ID of some kind. How to make this possible?

Please suggest other solutions to this issue.

Applicable Versions:

  • Netlify CMS version: 2.3.2
  • Gatsby: ^2.0.85
  • Git provider: Github
  • OS: MacOS Mojave 10.14.2

CMS configuration

collections:
  - name: "products"
    label: "Products"
    folder: "src/pages/produkter"
    create: true
    slug: "{{slug}}"
    editor:
      preview: false
    fields:
      - {label: "Template Key", name: "templateKey", widget: "hidden", default: "product-item"}
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Product category", name: "productCategory", widget: "relation", collection: "kategorier", searchFields: ["title"], valueField: "title", displayFields: ["title"]}
      - {label: "Produkt ID", name: "productId", widget: "string", default: "000000"}
      - {label: "ELNR", name: "ELNR", widget: "string", default: "000000"}
      - {label: "Packaging", name: "packaging", widget: "string", default: "1 stk"}
  - name: "kategorier"
    label: "Produkt kategorier"
    description: "Her kan du legge til/fjerne produktkategorier."
    folder: "src/pages/kategorier"
    create: true
    slug: "{{slug}}"
    fields:
      - {label: "Template Key", name: "templateKey", widget: "hidden", default: "category-item"}
      - {label: "Tittel", name: "title", widget: "string"}
      - {label: "Description", name: "body", widget: "markdown", required: false}
      - label: "Parent category (if any)"
        name: "parentCategory"
        widget: "relation"
        required: false
        collection: "kategorier"
        searchFields: ["title"]
        valueField: "title"
        hint: "Hvis denne er tom, er denne kategorien på høyeste nivå. Hvis den har en forelderkategori, er dette en subkategori"
      - {label: "SEO Beskrivelse", name: "seoDescription", required: false, widget: "text"}

Additional context

Thank you in advance, and thank you for providing Netlify CMS! I really enjoy it as a developer.

@FredrikSigvartsen FredrikSigvartsen changed the title Relation with valueField: title, Relation with valueField: title Feb 5, 2019
@FredrikSigvartsen FredrikSigvartsen changed the title Relation with valueField: title Relation with valueField: title looses relation on update Feb 5, 2019
@erquhart
Copy link
Contributor

erquhart commented Feb 5, 2019

There's more than one way to handle this, but I'm starting to think the approach championed by @Undistraction might be best, as it's not a hard feature to add. That is, providing placeholders in default values, including a uuid placeholder, so you can do:

  fields:
    - { name: id, widget: hidden, default: "{{uuid}}" }

@Undistraction I'm not seeing an issue specific to this but I know we've discussed it. Please link if you feel there's an issue that this is duplicating.

Update:

There's the potential for this to get hacky, though. UUID is a straightforward use case, but if we add other placeholders, like field names, it will be odd when edits to those fields don't impact a hidden field that uses them in interpolation. And when you consider that case, it becomes clear that we're not really looking for defaults, but values that are set or updated based on the situation. Which brings me back to events.

Having a hard time finding a case besides unique identifiers that this approach really works well for I guess. What do you think?

@Undistraction
Copy link
Contributor

Undistraction commented Feb 5, 2019

@erquhart I guess we are talking about several cases:

  1. One-time events like UID creation.
  2. Dynamically generated fields, like an entry-card title that is built on the fly from interpolating existing fields. Note: This is transient - the result of the interpolation is only used in the UI, not stored, so it will be up-to-date.
  3. Fields populated by interpolating the values of other fields.

I think the first two are good candidates for supporting interpolation, the third is, as you outline more problematic, because the result of the interpolation will only be correct when it is first created / populated. If any of the fields used in the interpolation change, the interpolated field will not be updated. To be honest, I hadn't really considered the third case. I had been seeing the use of interpolation as being a more dynamic thing used for displaying data rather than storing it.

@Undistraction
Copy link
Contributor

@erquhart Here is the issue I think you're thinking of: #1975

@Undistraction
Copy link
Contributor

Undistraction commented Feb 5, 2019

@FredrikSigvartsen The way I'm currently handling your problem is with a UUID widget that creates a field with a unique id for each collection item. The UUID will never change, so I use that as a stable connection for relations. The problem with this approach is that due to an existing bug, you cannot use another field to represent that relation to your users, so they will see each relation listed by its UUID instead of its title or other human-readable field. Unfortunately this makes this approach next to useless.

@erquhart
Copy link
Contributor

erquhart commented Feb 5, 2019

Note, the display value issue will be addressed in #1936, which should merge soon.

@Undistraction how are you handling the display of your UUID widget? Is it visible?

@Undistraction
Copy link
Contributor

Undistraction commented Feb 5, 2019

@erquhart Yes. It is visible. I couldn't find a way of preventing it from displaying. I'd post the source here but I don't have access to it at the moment. I think it was based on the widget outlined here.

Why do you ask?

@erquhart
Copy link
Contributor

erquhart commented Feb 5, 2019

Got it. Just curious to know how you were handling it.

Sent with GitHawk

@Undistraction
Copy link
Contributor

Undistraction commented Feb 5, 2019

@erquhart FWIW ideally it would be hidden as it isn't something a user should see or care about. I seem to remember the only way to hide a widget is to set it as of hidden type which is treated as a special case, so if my memory serves me, it would be great if hidden was a generic attribute instead of a type so it can be set on other types.

@FredrikSigvartsen
Copy link
Author

Thank you guys for good answers.

@Undistraction , since this uuid widget is not yet available, do you have an (code) example of your Custom UUID Widget?

@Undistraction
Copy link
Contributor

@FredrikSigvartsen on holiday with no access to my code, but take a look at the link in my above reply. I based it on the code outlined in that issue.

@FredrikSigvartsen
Copy link
Author

Thanks, solved the issue with the hacky UUID.

This is the custom widget I used:

import CMS from 'netlify-cms';
import ProductAreaPreview from './preview-templates/ProductAreaPreview';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import uuidv4 from 'uuid/v4';

export class UuidControl extends Component {
  static propTypes = {
    onChange: PropTypes.func.isRequired,
    forID: PropTypes.string,
    value: PropTypes.node,
    classNameWrapper: PropTypes.string.isRequired
  };

  static defaultProps = {
    value: ''
  };

  componentDidMount() {
    const { value, onChange } = this.props;

    if (!value) {
      onChange(uuidv4());
    }
  }

  render() {
    const { value, classNameWrapper, forID } = this.props;

    return (
      <span id={forID} className={classNameWrapper}>
        {value}
      </span>
    );
  }
}

Looking forward to the fix regarding the displayValue.

@abstracthat
Copy link

I just ran into this need for a UUID widget that is hidden too. Would be nice to have for sure. In the meantime I hacked the ref to also do element.parentElement.style.display = 'none' which seems to work fine for hiding the control in the UI but still saving the value to file. I also had to use React.forwardRef so that the validation did not throw. A supported solution would be much preferred of course.

@Mayaela
Copy link

Mayaela commented Aug 28, 2019

Another issue that could be fixed at the same time :
The relation widget doesn't allow the user to select a dropdown element if there is one element above it in the list with the same value in its valueField. It displays the first element with the same value instead of the one you clicked on. If you open the dropdown list again, all the options with the same value in valueField appeared as selected (blue background).
#2600

@stale
Copy link

stale bot commented Oct 29, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

@stale stale bot added the wontfix label Oct 29, 2019
@Undistraction
Copy link
Contributor

Not stale.

@stale stale bot removed the wontfix label Oct 29, 2019
@tobytraylor
Copy link

In #1063 they are running into the this issue and are proposing to solve it by allowing use of the slug.

@mhagmajer
Copy link
Contributor

Another way to handle this would be to allow relation to point to the relative file path of the related objects. The file paths don't change once created.

@cjustinobi
Copy link

Another way to handle this would be to allow relation to point to the relative file path of the related objects. The file paths don't change once created.

@mhagmajer could you give example how this would look like in the yaml file?

@erezrokah
Copy link
Contributor

erezrokah commented May 6, 2020

Closing this via #3659, as the relation widget now supports string templates and using the slug for the relation.
See example at the end of this page https://www.netlifycms.org/docs/widgets/#relation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants