简体   繁体   中英

Material UI Autocomplete- Popper not STUCk to the component which rendered it

Current Output of my Autocomplete is in the attached VIDEO Link wheree the atocomplete suggestions are dancing around the page as window scrolls: https://www.screencast.com/t/atbTdIaXpzu

I am trying to fix the Autocomplete suggestion to the Autocomplete control and somehow Auto Suggestions dropdown sticks to the autocomplete BUT the scrolling experience within the Autocomplete is not that smooth

Solution used as below:

Using AutoComplete Property PopperComponent ={PopperMy}

const PopperMy = function (props) {
  return <Popper {...props} placement="bottom-start" disablePortal={true} />;
};

or this popperVariant:

<Popper
      {...props}
      disablePortal={true}
      placement="bottom-start"
      popperOptions={{ positionFixed: true }}
    />

Any suggestions and fixed are appreciated. Thanks !

Adding the file contents for reference here:

import React, { useState, useEffect } from "react";
import {
  TextInputField,
  InputLabelField,
  BoxField,
  CustomWhiteTooltip,
} from "../../atoms";
import Autocomplete, {
  createFilterOptions,
} from "@material-ui/lab/Autocomplete";
import {
  IsArrayNotEmpty,
  IsNotEmpty,
  IsString,
  IsObject,
  IsFunction,
  ThrowException,
  IsObjectNotEmpty,
  ObjectHasKey,
  IsNotUndefined,
} from "../../../utility";
import UserMessages from "../../../constants/UserMessages";
import TextField from "@material-ui/core/TextField";
import { InfoIcon } from "../../../resources/ThemeIcons";
import { Popper } from "@material-ui/core";


const TypeaheadField = ({
  id = "",
  renderInputId = "",
  listOptions,
  mainListOptionsKey = IsString(mainListOptionsKey)
    ? mainListOptionsKey
    : "title",
  getPropertyFromSingleObject = IsString(getPropertyFromSingleObject)
    ? getPropertyFromSingleObject
    : false,
  //defaultSelected='',
  isCreatable = false,
  onChange,
  addNewLabel = "Add",
  disableClearable = false,
  className = "",
  textFieldClassName = "",
  isSelectMultiple = false,
  limitTags = -1,
  filterSelectedOptions = true,
  openOnFocus = true,
  blurOnSelect = false,
  labelAtTop = false,
  labelClassName = "",
  popupIcon,
  size = "small",
  disabled = false,
  variant = "standard",
  label = "",
  required = false,
  placeholder = "",
  fullWidth = true,
  value = "",
  ChipProps = {},
  inputLabelProps = {},
  helperText = "",
  error = false,
  onBlur = "",
  name = "",
  tooltipMessage = "",
  tooltipIcon = "",
  ...rest
}) => {
  /* Required props:  listOptions, onChange */
  const isListOptionsProvided = IsArrayNotEmpty(listOptions);
  const isOnChangeProvided = IsFunction(onChange);
  if (!isListOptionsProvided || !isOnChangeProvided) {
    //ThrowException(UserMessages.warnings.missingRequiredProps);
  }

  const [autovalue, setValue] = React.useState(value);

  useEffect(() => {
    const IsMultipleSelectAllowed = isSelectMultiple === true;
    if (IsMultipleSelectAllowed) {
      setValue(autovalue && IsArrayNotEmpty(autovalue) ? autovalue : []);
    } else if (!IsMultipleSelectAllowed) {
      setValue(autovalue && IsNotEmpty(autovalue) ? autovalue : null);
    }
  }, []);

  const handleOnChange = (event, newValue) => {
    let selectedValue = newValue;

    if (newValue && IsObject(newValue)) {
      if (newValue[mainListOptionsKey]) {
        // Create a new value from the user input
        if (newValue.type === "new") {
          if (IsString(listOptions[0])) {
            selectedValue = newValue.value;
            listOptions.push(newValue.value);
          } else {
            selectedValue = newValue.value;
            listOptions.push({
              [mainListOptionsKey]: newValue.value,
            });
          }
        }
      } else {
        const LastObject = IsArrayNotEmpty(newValue)
          ? newValue[newValue.length - 1]
          : null;
        const IsNewValueAdded =
          LastObject && LastObject.type === "new" && LastObject.value;
        if (IsNewValueAdded) {
          // Create a new value from the user input
          const CurrentValues =
            autovalue && IsArrayNotEmpty(autovalue) ? [...autovalue] : [];
          if (IsString(listOptions[0])) {
            selectedValue = [...CurrentValues, LastObject.value];
            listOptions.push(LastObject.value);
          } else {
            selectedValue = [
              ...CurrentValues,
              { [mainListOptionsKey]: LastObject.value },
            ];
            listOptions.push({ [mainListOptionsKey]: LastObject.value });
          }
        }
      }
    }

    setValue(selectedValue);
    if (
      getPropertyFromSingleObject !== false &&
      isSelectMultiple === false &&
      IsObjectNotEmpty(selectedValue) &&
      ObjectHasKey(selectedValue, getPropertyFromSingleObject)
    ) {
      onChange(selectedValue[getPropertyFromSingleObject]);
      return;
    }
    onChange(selectedValue);
  };

  const handleFilterOptions = (options, params) => {
    const filter = createFilterOptions();
    const filtered = filter(options, params);

    // Suggest the creation of a new value
    const IsSuggestNewValue = params.inputValue !== "" && isCreatable === true;
    if (IsSuggestNewValue) {
      filtered.push({
        value: params.inputValue,
        type: "new",
        [mainListOptionsKey]: `${addNewLabel} "${params.inputValue}"`,
      });
    }
    return filtered;
  };

  const handleGetOptionLabel = (option) => {
    if (typeof option === "string") {
      return option;
    }
    return option ? option[mainListOptionsKey] : null;
  };

  const handleGetOptionSelected = (option, value) => {
    if (value && IsObject(value) && IsObjectNotEmpty(value)) {
      return option[mainListOptionsKey] === value[mainListOptionsKey];
    } else if (
      option &&
      IsObject(option) &&
      IsObjectNotEmpty(option) &&
      value &&
      IsString(value) &&
      IsNotEmpty(value)
    ) {
      return option[mainListOptionsKey] === value;
    } else {
      return option === value;
    }
  };

  const handleEmptyValue = (valueParam) => {
    /**
     * TODO:: Add these in utility folder.
     */
    if (isSelectMultiple) {
      return value && IsArrayNotEmpty(value)
        ? value
        : valueParam && IsArrayNotEmpty(valueParam)
        ? valueParam
        : [];
    } else {
      if (IsObject(valueParam) || IsObject(value)) {
        return IsNotUndefined(value) &&
          value !== null &&
          IsObjectNotEmpty(value)
          ? value
          : IsNotUndefined(valueParam) &&
            valueParam !== null &&
            IsObjectNotEmpty(valueParam)
          ? valueParam
          : null;
      } else if (IsString(valueParam) || IsString(value)) {
        return IsNotEmpty(value)
          ? value
          : IsNotEmpty(valueParam)
          ? valueParam
          : null;
      }
    }
  };

  const handleOnBlur = () => {
    if (IsFunction(onBlur)) {
      onBlur();
    }
  };

  const autocompleteValue = handleEmptyValue(autovalue);

  const inputRequired =
    required === true &&
    (isSelectMultiple
      ? !IsArrayNotEmpty(autocompleteValue)
      : !IsNotEmpty(autocompleteValue));

  return (
    <Autocomplete
      className={className}
      multiple={isSelectMultiple}
      value={autocompleteValue}
      filterSelectedOptions={filterSelectedOptions}
      id={id}
      size={size}
      ChipProps={ChipProps}
      disableClearable={disableClearable}
      popupIcon={popupIcon}
      openOnFocus={openOnFocus}
      blurOnSelect={blurOnSelect}
      options={listOptions}
      limitTags={limitTags}
      onChange={handleOnChange}
      disabled={disabled}
      filterOptions={handleFilterOptions}
      getOptionLabel={handleGetOptionLabel}
      getOptionSelected={handleGetOptionSelected}
      
      name={name}
      onBlur={handleOnBlur}
      renderInput={(params) => (
        <div>
       <TextField
            {...params}
            id={renderInputId ? renderInputId : label}
            variant={variant}
            label={!labelAtTop && label}
            className={textFieldClassName}
            required={inputRequired}
            //onChange={()=>{}}
            placeholder={placeholder}
            fullWidth={fullWidth}
            InputLabelProps={inputLabelProps}
            helperText={helperText}
            error={error}           
          /> 
        </div>
      )}
    />
  );
};

export default TypeaheadField;

I'd like to see more about your code to have a better context. The first suggestion is to use the prop anchorEl and reference your Textfield. You can find more about it and examples in the documentation here:

https://material-ui.com/es/components/popper/

And also I don't know if you are using the Autocomplete component directly so let me know if you are.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM