$(this)未在jQuery UI对话框“open”选项中设置

erhoui1w  于 2023-10-17  发布在  jQuery
关注(0)|答案(2)|浏览(108)

在文字游戏的底部有4个按钮,用于打开jQuery UI对话框,其中包含游戏字典中的某些单词:

我试图通过创建以下函数来简化游戏代码:

// select word using the filterFunc and then concat them all to a string
function filterWords(filterFunc) {
    // the words already filtered and assigned to the dialog's innerHTML
    if ($(this).html().length > 1000) {
        return (ev, ui) => {};
    }

    // filter the keys of HASHED dictionary by calling the filterFunc on each
    const filtered = Object.keys(HASHED)
        .filter(word => filterFunc(word))
        .reduce((result, word) => {
            return result + 
                '<p><span class="tile">' + word + '</span> ' + HASHED[word] + '</p>'
        }, '');

    // return the closure expected by the dialog's "open" option
    return (ev, ui) => {
        $(this).html(filtered);
        const title = $(this).dialog('option', 'title');
        console.log(title + ': ' + filtered.length + ' chars');
    };
}

我希望jQuery UI对话框“open”选项需要一个function (ev, ui) {},这就是我试图通过我的新函数给予的:

const twoDlg = $('#twoDlg').dialog({
    modal: true,
    appendTo: '#fullDiv',
    autoOpen: false,
    open: filterWords(word => word.length == 2),
    buttons: {
        'Close': function() {
            $(this).dialog('close');
        }
    }
});

下面是另一个对话框:

const rare2Dlg = $('#rare2Dlg').dialog({
    modal: true,
    appendTo: '#fullDiv',
    autoOpen: false,
    open: filterWords(word => word.indexOf('X') >= 0),
    buttons: {
        'Close': function() {
            $(this).dialog('close');
        }
    }
});

不幸的是,现在我得到了错误消息:

jquery.js:4095  Uncaught TypeError: Cannot read properties of undefined (reading 'length')
    at filterWords (test?player=abcde:833:594)
    at HTMLDocument.<anonymous> (test?player=abcde:835:139)
    at mightThrow (jquery.js:3802:29)
    at process (jquery.js:3870:12)

这表明$(this).html()在我的闭包中是无效的。
有办法让它工作吗?

更新:

我已经准备了一个jsFiddle与3个对话框和3个按钮打开。方法filterWordsWorks()可以工作,但是有太多的重复代码。注解掉的方法open: filterWordsBroken(word => word.length == 2),失败。
下面是同样的演示代码,内联到Stackoverflow:

'use strict';

const HASHED = {
  "one": "Word description 1",
  "two": "Word description 2",
  "three": "Word description 3",
  "four": "Word description 4",
  "five": "Word description 5",
  "six": "Word description 6",
  "seven": "Word description 7"
};

// select word using the filterFunc and then concat them all to a string
function filterWordsBroken(filterFunc) {
  // the words already filtered and assigned to the dialog's innerHTML
  if ($(this).html().length > 1000) {
    return (ev, ui) => {};
  }

  // filter the keys of HASHED dictionary by calling the filterFunc on each
  const filtered = Object.keys(HASHED)
    .filter(word => filterFunc(word))
    .reduce((result, word) => {
      return result +
        '<p>' + word + ': ' + HASHED[word] + '</p>'
    }, '');

  // return the closure expected by the dialog's "open" option
  return (ev, ui) => {
    $(this).html(filtered);
    const title = $(this).dialog('option', 'title');
    console.log(title + ': ' + filtered.length + ' chars');
  };
}

// select word using the filterFunc and then concat them all to a string
function filterWordsWorks(filterFunc) {
  return Object.keys(HASHED)
    .filter(word => filterFunc(word))
    .reduce((result, word) => {
      return result +
        '<p>' + word + ': ' + HASHED[word] + '</p>'
    }, '');
}

jQuery(document).ready(function($) {
  const twoDlg = $('#twoDlg').dialog({
    modal: true,
    autoOpen: false,
    //open: filterWordsBroken(word => word.length == 2),
    open: function(ev, ui) {
      // prevent this code from running twice
      if ($(this).html().length < 1000) {
        const filtered = filterWordsWorks(word => word.length == 2);
        $(this).html(filtered);
        const title = $(this).dialog('option', 'title');
        console.log(title + ': ' + filtered.length);
      }
    }
  });
  const threeDlg = $('#threeDlg').dialog({
    modal: true,
    autoOpen: false,
    //open: filterWordsBroken(word => word.length == 3),
    open: function(ev, ui) {
      // prevent this code from running twice
      if ($(this).html().length < 1000) {
        const filtered = filterWordsWorks(word => word.length == 3);
        $(this).html(filtered);
        const title = $(this).dialog('option', 'title');
        console.log(title + ': ' + filtered.length);
      }
    }
  });
  const fourDlg = $('#fourDlg').dialog({
    modal: true,
    autoOpen: false,
    //open: filterWordsBroken(word => word.length == 3),
    open: function(ev, ui) {
      // prevent this code from running twice
      if ($(this).html().length < 1000) {
        const filtered = filterWordsWorks(word => word.length == 4);
        $(this).html(filtered);
        const title = $(this).dialog('option', 'title');
        console.log(title + ': ' + filtered.length);
      }
    }
  });

  $('#twoBtn').button().click(function(ev) {
    ev.preventDefault();
    twoDlg.dialog('open');
  });

  $('#threeBtn').button().click(function(ev) {
    ev.preventDefault();
    threeDlg.dialog('open');
  });

  $('#fourBtn').button().click(function(ev) {
    ev.preventDefault();
    fourDlg.dialog('open');
  });
});
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-ui@1/dist/themes/redmond/jquery-ui.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ui@1/dist/jquery-ui.min.js"></script>

<!-- beware: the twoDlg will be empty -->
<DIV ID="twoDlg" TITLE="2 letters"></DIV>
<DIV ID="threeDlg" TITLE="3 letters"></DIV>
<DIV ID="fourDlg" TITLE="4 letters"></DIV>

<BUTTON ID="twoBtn">2 letters</BUTTON>
<BUTTON ID="threeBtn">3 letters</BUTTON>
<BUTTON ID="fourBtn">4 letters</BUTTON>
uelo1irk

uelo1irk1#

你想用多少就用多少。
这不是对这个问题的直接回答,而是一个x/y的例子,说明你的目标是什么:更少的代码
既然你指出你的愿望是更少的代码,这里有一个更简单的例子。

  • 在按钮和对话框中使用一些数据属性
  • 请注意,对话框3没有任何内容,并使用默认代码wordLength: 3,
  • 为所有按钮使用一个类,以便在代码中将它们作为目标
  • 为所有对话框使用一个类,以便在代码中针对它们
  • 按钮上的数据属性来说明它指向哪个对话框。
  • 使用了一些文字作为例子(带反引号)
`${myvar}text more text${anothervar} fun`;
  • 从按钮单击中删除了preventDefault,而是在元素上使用type="button"
  • 链接$('.my-letter-dialog') .on("dialogopen".dialog(- order很重要,因为.dialog(不返回jQuery,但事件处理程序会返回。

你可以从一个对话框创建一个对话框-添加了一个“5”字母的例子,但它可以是所有的。

'use strict';

const HASHED = {
  "one": "Word description 1",
  "two": "Word description 2",
  "three": "Word description 3",
  "four": "Word description 4",
  "five": "Word description 5",
  "six": "Word description 6",
  "seven": "Word description 7"
};
jQuery(function($) {
  function filterFunc(word, len) {
    //console.log(word, len, word.length == len);
    return word.length == len;
  }
  $('.my-letter-dialog')
    .on("dialogopen", function(event, ui) {
      let elWLen = $(this).data('wordlength');
      let wordLen = !!elWLen ? elWLen : $(this).dialog("option", "wordLength");
      console.log(wordLen);
      if ($(this).html().length > 1000) {
        return (ev, ui) => {};
      }
      const filtered = Object.keys(HASHED)
        .filter(word => filterFunc(word, wordLen))
        .reduce((result, word) => {
          return `${result}<p>${word}:${HASHED[word]}</p>`
        }, '');
      //console.log('filtered:', filtered)
      $(this).html(filtered);
      const title = $(this).dialog('option', 'title');
      const newTitle = `${title}:${filtered.length} chars`;
      $(this).dialog('option', 'title', newTitle);
    })
    .dialog({
      modal: true,
      autoOpen: false,
      wordLength: 3,
      filterFunc: filterFunc
    });

  $('.my-letter-button').button()
    .on("click", function(ev) {
      const targ = $(this).data('targetselector');
      $(targ).dialog('open');
    });
});
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-ui@1/dist/themes/redmond/jquery-ui.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ui@1/dist/jquery-ui.min.js"></script>

<!-- beware: the twoDlg will be empty -->
<div class="my-letter-dialog" id="twoDlg" data-wordlength="2" title="2 letters"></div>
<div class="my-letter-dialog" id="threeDlg" title="3 letters"></div>
<div class="my-letter-dialog" id="fourDlg" data-wordlength="4" title="4 letters"></div>

<button class="my-letter-button" type="button" id="twoBtn" data-targetselector="#twoDlg">2 letters</button>
<button class="my-letter-button" type="button" id="threeBtn" data-targetselector="#threeDlg">3 letters</button>
<button class="my-letter-button" type="button" id="fourBtn" data-targetselector="#fourDlg">4 letters</button>
a6b3iqyw

a6b3iqyw2#

这是相当粗略的,但在这里我创建了一个名为filterWords的UI小部件方法,并将其添加到ui.dialog中,然后展示了如何使用按钮调用它。
另外,我添加了一个在对话框打开时调用的方法。
备注:

  • 对话框filterWords也会触发打开
  • 注解掉了这个演示的一部分代码,因为我没有可用的HASHED
  • 添加了一个开放的处理程序,如果你想去的方向
  • 注意小部件代码如何使用this.element
  • 小部件文档:https://jqueryui.com/widget/
  • 注意对话框如何作为$(this)可用,如我在RAW函数中使用html的$(this).find('.words')元素日志所示
  • 我添加了一些额外的代码,以显示您的单词计数如何成为选项wordcount:2,

可能还有其他方法可以使其更有效,但这里我只是在这里展示了很多可用的选项。

$.widget("ui.dialog", $.ui.dialog, {
  filterWords: function(event) {
    let count = this.options.wordcount;
    console.log(count);
    console.log('we are here!');
    //console.log(this.element);
    let myWords = this.element.find('.words');
    console.log('words:', myWords.length, myWords.html());
    $(this).trigger('open');

    /*
           // the words already filtered and assigned to the dialog's innerHTML
    if ($(this).find('.words').html().length > 1000) {
        return (ev, ui) => {};
    }

    // filter the keys of HASHED dictionary by calling the filterFunc on each
    const filtered = Object.keys(HASHED)
        .filter(word => filterFunc(word))
        .reduce((result, word) => {
            return result + 
                '<p><span class="tile">' + word + '</span> ' + HASHED[word] + '</p>'
        }, '');

    // return the closure expected by the dialog's "open" option
    return (ev, ui) => {
        $(this).html(filtered);
        const title = $(this).dialog('option', 'title');
        console.log(title + ': ' + filtered.length + ' chars');
    };
     */
  }
});

function filterWordsRaw(event, ui) {
  console.log('in RAW form');
  console.log($(this).find('.words').html());
  // the words already filtered and assigned to the dialog's innerHTML
  if ($(this).html().length > 1000) {
    return (ev, ui) => {};
  }
  /* commented out as I do not have HASHED defined 
    // filter the keys of HASHED dictionary by calling the filterFunc on each
    const filtered = Object.keys(HASHED)
      .filter(word => filterFunc(word))
      .reduce((result, word) => {
        return result +
          '<p><span class="tile">' + word + '</span> ' + HASHED[word] + '</p>'
      }, '');

    // return the closure expected by the dialog's "open" option
    return (ev, ui) => {
      $(this).html(filtered);
      const title = $(this).dialog('option', 'title');
      console.log(title + ': ' + filtered.length + ' chars');
    };
    */
}

/* just to show we did this */
function handleOpen(event) {
  console.log('opened');
  console.log(event.target === this);
}

$(".selector").dialog({
  modal: true,
  appendTo: '#fullDiv',
  autoOpen: false,
  open: handleOpen,
  wordcount: 2,
  buttons: {
    'Close': function() {
      $(this).dialog('close');
    }
  }
});

$(".selector").on("dialogopen", filterWordsRaw);

$('.go-do-it').on('click', function(event) {
  console.log('hi');
  $(".selector").dialog("filterWords");
});
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<script src="https://code.jquery.com/ui/1.13.2/jquery-ui.min.js"></script>
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/redmond/jquery-ui.css">
<div class="container">
  <button type="button" class="go-do-it">Click</button>
</div>

<div class="selector" title="Dialog Title">
  <span class="words">one fish two fish red fish blue fish</span>
</div>
<div id="fullDiv"></div>

相关问题