复杂的选择和输入文本字段组合,具有添加更多和删除选项。

huangapple go评论99阅读模式
英文:

Complex Select and Input Text Filed Combo with add more and remove option

问题

我有一个下拉框,还有一个文本字段。用户可以选择他们提供的链接类型,然后在输入文本中提供链接。此外,他们可以添加不同类型的更多链接。每种类型只能有一个链接。如果他们犯了错误,他们可以移除任何链接。

我陷入了这个问题,无法找到任何简单的解决方案。

所需的最终输出是一个数组 projectLinks。[{web:"url"},{android:"url"}]

请帮忙。

复杂的选择和输入文本字段组合,具有添加更多和删除选项。
React 代码:

  1. import { useState } from "react";
  2. import MainLayout from "./layouts/MainLayout";
  3. const linkOptions = [
  4. { value: "web", label: "Web" },
  5. { value: "android", label: "Android" },
  6. { value: "ios", label: "iOS" },
  7. { value: "youtube", label: "Youtube" },
  8. { value: "twitter", label: "Twitter" }
  9. ];
  10. type ProjectLinks = [
  11. { web?: string },
  12. { android?: string },
  13. { ios?: string },
  14. { youtube?: string },
  15. { twitter?: string }
  16. ];
  17. export default function App() {
  18. const [projectLinks, setProjectLinks] = useState<ProjectLinks>();
  19. const [numberOfLinks, setNumberOfLinks] = useState(1);
  20. const handleChangeOption = (event: any) => {
  21. console.log(event.target.value);
  22. };
  23. const submit = () => {
  24. console.log("已提交");
  25. };
  26. const handleAddLink = () => {
  27. setNumberOfLinks((prev) => prev + 1);
  28. };
  29. const handleRemoveLink = () => {
  30. setNumberOfLinks((prev) => prev - 1);
  31. };
  32. return (
  33. <MainLayout>
  34. <div className="flex flex-col">
  35. {[...Array(numberOfLinks)].map((_, index) => (
  36. <LinkField
  37. key={index}
  38. handleChangeOption={handleChangeOption}
  39. handleAddLink={handleAddLink}
  40. handleRemoveLink={handleRemoveLink}
  41. />
  42. ))}
  43. <button className="btn btn-active mt-8" onClick={submit}>
  44. 按钮
  45. </button>
  46. </div>
  47. </MainLayout>
  48. );
  49. }
  50. function LinkField({
  51. handleChangeOption,
  52. handleAddLink,
  53. handleRemoveLink
  54. }: {
  55. handleChangeOption: (event: any) => void;
  56. handleAddLink: () => void;
  57. handleRemoveLink: () => void;
  58. }) {
  59. return (
  60. <div className="mt-1 mb-1">
  61. <div className="flex justify-between">
  62. <select onChange={handleChangeOption} className="select select-primary">
  63. {linkOptions.map((option, index) => (
  64. <option key={index} value={option.value}>
  65. {option.label}
  66. </option>
  67. ))}
  68. </select>
  69. <input
  70. type="text"
  71. placeholder="example.com"
  72. className="input input-bordered ml-1 mr-1"
  73. />
  74. <button
  75. className="btn btn-md btn-active ml-1 mr-1"
  76. onClick={handleAddLink}
  77. >
  78. 添加
  79. </button>
  80. <button
  81. className="btn btn-md btn-active ml-1 mr-1"
  82. onClick={handleRemoveLink}
  83. >
  84. 移除
  85. </button>
  86. </div>
  87. </div>
  88. );
  89. }

我正在使用 tailwindcss 和 daisyui。

英文:

I have a drop down also a text filed. User can select which kind of link they are providing and then give link in input text.
Also they can add more links of different kind. Only 1 link of 1 kind.
If they made mistake they can remove any link.

I am stuck in this problem and unable to figure out any simple solution.

Final output required is an array projectLinks. [{web:"url"},{android:"url"}]

Please help.

复杂的选择和输入文本字段组合,具有添加更多和删除选项。
React Code:

  1. import MainLayout from &quot;./layouts/MainLayout&quot;;
  2. const linkOptions = [
  3. { value: &quot;web&quot;, label: &quot;Web&quot; },
  4. { value: &quot;android&quot;, label: &quot;Android&quot; },
  5. { value: &quot;ios&quot;, label: &quot;iOS&quot; },
  6. { value: &quot;youtube&quot;, label: &quot;Youtube&quot; },
  7. { value: &quot;twitter&quot;, label: &quot;Twitter&quot; }
  8. ];
  9. type ProjectLinks = [
  10. { web?: string },
  11. { android?: string },
  12. { ios?: string },
  13. { youtube?: string },
  14. { twitter?: string }
  15. ];
  16. export default function App() {
  17. const [projectLinks, setProjectLinks] = useState&lt;ProjectLinks&gt;();
  18. const [numberOfLinks, setNumberOfLinks] = useState(1);
  19. const handleChangeOption = (event: any) =&gt; {
  20. console.log(event.target.value);
  21. };
  22. const submit = () =&gt; {
  23. console.log(&quot;Submitted&quot;);
  24. };
  25. const handleAddLink = () =&gt; {
  26. setNumberOfLinks((prev) =&gt; prev + 1);
  27. };
  28. const handleRemoveLink = () =&gt; {
  29. setNumberOfLinks((prev) =&gt; prev - 1);
  30. };
  31. return (
  32. &lt;MainLayout&gt;
  33. &lt;div className=&quot;flex flex-col&quot;&gt;
  34. {[...Array(numberOfLinks)].map((_, index) =&gt; (
  35. &lt;LinkField
  36. key={index}
  37. handleChangeOption={handleChangeOption}
  38. handleAddLink={handleAddLink}
  39. handleRemoveLink={handleRemoveLink}
  40. /&gt;
  41. ))}
  42. &lt;button className=&quot;btn btn-active mt-8&quot; onClick={submit}&gt;
  43. Button
  44. &lt;/button&gt;
  45. &lt;/div&gt;
  46. &lt;/MainLayout&gt;
  47. );
  48. }
  49. function LinkField({
  50. handleChangeOption,
  51. handleAddLink,
  52. handleRemoveLink
  53. }: {
  54. handleChangeOption: (event: any) =&gt; void;
  55. handleAddLink: () =&gt; void;
  56. handleRemoveLink: () =&gt; void;
  57. }) {
  58. return (
  59. &lt;div className=&quot;mt-1 mb-1&quot;&gt;
  60. &lt;div className=&quot;flex justify-between&quot;&gt;
  61. &lt;select onChange={handleChangeOption} className=&quot;select select-primary&quot;&gt;
  62. {linkOptions.map((option, index) =&gt; (
  63. &lt;option key={index} value={option.value}&gt;
  64. {option.label}
  65. &lt;/option&gt;
  66. ))}
  67. &lt;/select&gt;
  68. &lt;input
  69. type=&quot;text&quot;
  70. placeholder=&quot;example.com&quot;
  71. className=&quot;input input-bordered ml-1 mr-1&quot;
  72. /&gt;
  73. &lt;button
  74. className=&quot;btn btn-md btn-active ml-1 mr-1&quot;
  75. onClick={handleAddLink}
  76. &gt;
  77. Add
  78. &lt;/button&gt;
  79. &lt;button
  80. className=&quot;btn btn-md btn-active ml-1 mr-1&quot;
  81. onClick={handleRemoveLink}
  82. &gt;
  83. Remove
  84. &lt;/button&gt;
  85. &lt;/div&gt;
  86. &lt;/div&gt;
  87. );
  88. }

I am using tailwindcss with daisyui.

答案1

得分: 1

我通过避免大部分状态变量并使用表单提交来解决了这个问题。

  1. import { useState } from "react";
  2. import MainLayout from "./layouts/MainLayout";
  3. const linkOptions = [
  4. { value: "web", label: "Web" },
  5. { value: "android", label: "Android" },
  6. { value: "ios", label: "iOS" },
  7. { value: "youtube", label: "Youtube" },
  8. { value: "twitter", label: "Twitter" }
  9. ];
  10. type ProjectLinks = [
  11. { web?: string },
  12. { android?: string },
  13. { ios?: string },
  14. { youtube?: string },
  15. { twitter?: string }
  16. ];
  17. export default function App() {
  18. const [count, setCount] = useState(1);
  19. const [urlError, setUrlError] = useState(false);
  20. const submit = (event: any) => {
  21. let urlTypeArray: string[] = [];
  22. let urlArray: string[] = [];
  23. let projectLinks: ProjectLinks[] = [];
  24. [...Array(count)].map((_, index) => {
  25. let url =
  26. count === 1 ? event.target.url.value : event.target.url[index].value;
  27. let urlType =
  28. count === 1
  29. ? event.target.urlType.value
  30. : event.target.urlType[index].value;
  31. if (
  32. urlTypeArray.includes(urlType) ||
  33. urlArray.includes(url) ||
  34. !url.length
  35. ) {
  36. setUrlError(true);
  37. return null;
  38. } else {
  39. urlTypeArray.push(urlType);
  40. urlArray.push(url);
  41. var urlObj: any = {};
  42. urlObj[urlType] = url;
  43. projectLinks = [...projectLinks, urlObj];
  44. }
  45. });
  46. if (!urlError && projectLinks.length) {
  47. console.log(projectLinks);
  48. // 提交到API的URL操作
  49. }
  50. event.preventDefault();
  51. };
  52. const handleAddLink = () => {
  53. setCount((prev) => (prev < linkOptions.length ? prev + 1 : prev));
  54. };
  55. const handleRemoveLink = () => {
  56. setCount((prev) => (prev > 1 ? prev - 1 : prev));
  57. };
  58. return (
  59. <MainLayout>
  60. <form className="flex flex-col" onSubmit={submit}>
  61. {[...Array(count)].map((link, index) => (
  62. <LinkField
  63. key={index}
  64. index={index}
  65. handleAddLink={handleAddLink}
  66. handleRemoveLink={handleRemoveLink}
  67. />
  68. ))}
  69. <button
  70. className={`btn ${urlError ? "btn-disabled" : "btn-active"} mt-8`}
  71. >
  72. Button
  73. </button>
  74. {urlError ? (
  75. <div
  76. className="toast cursor-pointer"
  77. onClick={() => setUrlError(false)}
  78. >
  79. <div className="alert alert-error">
  80. <span>Duplicate URL Type or URL or URL is Empty.</span>
  81. </div>
  82. </div>
  83. ) : null}
  84. </form>
  85. </MainLayout>
  86. );
  87. }
  88. function LinkField({
  89. handleAddLink,
  90. handleRemoveLink,
  91. index
  92. }: {
  93. handleAddLink: () => void;
  94. handleRemoveLink: () => void;
  95. index: number;
  96. }) {
  97. return (
  98. <div className="mt-1 mb-1">
  99. <div className="flex justify-between">
  100. <select name="urlType" className="select select-primary">
  101. {linkOptions.map((option, index) => (
  102. <option key={index} value={option.value}>
  103. {option.label}
  104. </option>
  105. ))}
  106. </select>
  107. <input
  108. type="text"
  109. name="url"
  110. placeholder="example.com"
  111. className="input input-bordered ml-1 mr-1"
  112. />
  113. <button
  114. className={`btn ${
  115. index === linkOptions.length - 1 ? "btn-disabled" : ""
  116. } ml-1 mr-1`}
  117. onClick={handleAddLink}
  118. type="button"
  119. >
  120. Add
  121. </button>
  122. <button
  123. className={`btn ${index === 0 ? "btn-disabled" : ""} ml-1 mr-1`}
  124. onClick={handleRemoveLink}
  125. // type="button"
  126. >
  127. Remove
  128. </button>
  129. </div>
  130. </div>
  131. );
  132. }
英文:

I solved it by avoiding most of the state variables and used form submit.

  1. import { useState } from &quot;react&quot;;
  2. import MainLayout from &quot;./layouts/MainLayout&quot;;
  3. const linkOptions = [
  4. { value: &quot;web&quot;, label: &quot;Web&quot; },
  5. { value: &quot;android&quot;, label: &quot;Android&quot; },
  6. { value: &quot;ios&quot;, label: &quot;iOS&quot; },
  7. { value: &quot;youtube&quot;, label: &quot;Youtube&quot; },
  8. { value: &quot;twitter&quot;, label: &quot;Twitter&quot; }
  9. ];
  10. type ProjectLinks = [
  11. { web?: string },
  12. { android?: string },
  13. { ios?: string },
  14. { youtube?: string },
  15. { twitter?: string }
  16. ];
  17. export default function App() {
  18. const [count, setCount] = useState(1);
  19. const [urlError, setUrlError] = useState(false);
  20. const submit = (event: any) =&gt; {
  21. let urlTypeArray: string[] = [];
  22. let urlArray: string[] = [];
  23. let projectLinks: ProjectLinks[] = [];
  24. [...Array(count)].map((_, index) =&gt; {
  25. let url =
  26. count === 1 ? event.target.url.value : event.target.url[index].value;
  27. let urlType =
  28. count === 1
  29. ? event.target.urlType.value
  30. : event.target.urlType[index].value;
  31. if (
  32. urlTypeArray.includes(urlType) ||
  33. urlArray.includes(url) ||
  34. !url.length
  35. ) {
  36. setUrlError(true);
  37. return null;
  38. } else {
  39. urlTypeArray.push(urlType);
  40. urlArray.push(url);
  41. var urlObj: any = {};
  42. urlObj[urlType] = url;
  43. projectLinks = [...projectLinks, urlObj];
  44. }
  45. });
  46. if (!urlError &amp;&amp; projectLinks.length) {
  47. console.log(projectLinks);
  48. // Action for URL submit to API
  49. }
  50. event.preventDefault();
  51. };
  52. const handleAddLink = () =&gt; {
  53. setCount((prev) =&gt; (prev &lt; linkOptions.length ? prev + 1 : prev));
  54. };
  55. const handleRemoveLink = () =&gt; {
  56. setCount((prev) =&gt; (prev &gt; 1 ? prev - 1 : prev));
  57. };
  58. return (
  59. &lt;MainLayout&gt;
  60. &lt;form className=&quot;flex flex-col&quot; onSubmit={submit}&gt;
  61. {[...Array(count)].map((link, index) =&gt; (
  62. &lt;LinkField
  63. key={index}
  64. index={index}
  65. handleAddLink={handleAddLink}
  66. handleRemoveLink={handleRemoveLink}
  67. /&gt;
  68. ))}
  69. &lt;button
  70. className={`btn ${urlError ? &quot;btn-disabled&quot; : &quot;btn-active&quot;} mt-8`}
  71. &gt;
  72. Button
  73. &lt;/button&gt;
  74. {urlError ? (
  75. &lt;div
  76. className=&quot;toast cursor-pointer&quot;
  77. onClick={() =&gt; setUrlError(false)}
  78. &gt;
  79. &lt;div className=&quot;alert alert-error&quot;&gt;
  80. &lt;span&gt;Duplicate URL Type or URL or URL is Empty.&lt;/span&gt;
  81. &lt;/div&gt;
  82. &lt;/div&gt;
  83. ) : null}
  84. &lt;/form&gt;
  85. &lt;/MainLayout&gt;
  86. );
  87. }
  88. function LinkField({
  89. handleAddLink,
  90. handleRemoveLink,
  91. index
  92. }: {
  93. handleAddLink: () =&gt; void;
  94. handleRemoveLink: () =&gt; void;
  95. index: number;
  96. }) {
  97. return (
  98. &lt;div className=&quot;mt-1 mb-1&quot;&gt;
  99. &lt;div className=&quot;flex justify-between&quot;&gt;
  100. &lt;select name=&quot;urlType&quot; className=&quot;select select-primary&quot;&gt;
  101. {linkOptions.map((option, index) =&gt; (
  102. &lt;option key={index} value={option.value}&gt;
  103. {option.label}
  104. &lt;/option&gt;
  105. ))}
  106. &lt;/select&gt;
  107. &lt;input
  108. type=&quot;text&quot;
  109. name=&quot;url&quot;
  110. placeholder=&quot;example.com&quot;
  111. className=&quot;input input-bordered ml-1 mr-1&quot;
  112. /&gt;
  113. &lt;button
  114. className={`btn ${
  115. index === linkOptions.length - 1 ? &quot;btn-disabled&quot; : &quot;&quot;
  116. } ml-1 mr-1`}
  117. onClick={handleAddLink}
  118. type=&quot;button&quot;
  119. &gt;
  120. Add
  121. &lt;/button&gt;
  122. &lt;button
  123. className={`btn ${index === 0 ? &quot;btn-disabled&quot; : &quot;&quot;} ml-1 mr-1`}
  124. onClick={handleRemoveLink}
  125. // type=&quot;button&quot;
  126. &gt;
  127. Remove
  128. &lt;/button&gt;
  129. &lt;/div&gt;
  130. &lt;/div&gt;
  131. );
  132. }

huangapple
  • 本文由 发表于 2023年6月1日 15:46:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76379701.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定