0

THIS IS NOT A DUPLICATE. THE SUGGESTED "DUPLICATE" IS IN REFERENCE TO OBJECTS THAT EXIST IN HTML, BUT HAVE NOT YET DRAWN IN THE DOM WHICH IS USUALLY REMEDIED USING THE ONLOAD EVENT. MY ISSUE IS SIMILAR, BUT THE CONTENT IS BEING CREATED -AFTER- THE PAGE HAS COMPLETELY RENDERED

The issue I am having is after replacing html, I can not register events on the newly formed html. The 'this' in the loop, doesn't seem to propegate with the new change, and there doesn't appear to be anyway to set it up.

What I would like it to do, is :

  • Completely replace an html element (including itself as the parent, not just the inner content)
  • Register events on the newly formed html during the replacement.

Following is a very basic demonstration of the problem.

HTML

<html>
<head>
<script src="https://code.jquery.com/jquery-2.1.4.min.js" type="text/javascript"></script>
<script src="MyNewSelect.js" type="text/javascript"></script>
<script type="text/javascript">
    $(document).ready(function() {
        $('#SomeOldSelect').MyNewSelect();
    });
</script>
</head>
<body>
<select id="SomeOldSelect">
    <option value="foo">Bar</option>
</select>
</body>
</html>

jQuery function

(function( $ ) {

    $.fn.MyNewSelect = function() {

        this.each(function(){

            // Rebuild the HTML from select tag
            $(this).children('option').each(function(){
                nHtml += '<span value="' + $(this).text() + '"><a class="fa" style="color: ' + $(this).val() + ';">&#xf0c8;</a>' + $(this).text() + '</span>';
            });

            nHtml += '<div id="' + $(this).attr("id") + '">' + nHtml + '</div>';

            // Replace select tag with new html
            $(this).replaceWith(nHtml);


            // Register click event on new html
            $(this).find('span').click(function() {
                console.log($(this).text());
            });
        }
    }
}( jQuery ));
Kraang Prime
  • 9,981
  • 10
  • 58
  • 124
  • How are the relevant event-handlers assigned in the first place? The easiest method would be create a log (an array perhaps) of assigned event-handlers, and then attach the events held in that 'log' at the point of creating the new element(s). – David Thomas Aug 24 '15 at 00:06
  • @DavidThomas - See the `$(this).find('span').click(function() {` line in the jQuery code. That is the event handler creation, and as you can see, there is console.log() . That event registration doesn't occur, as $(this), isn't being seen as containing that span -- even though it does at that point as it is after the html has been replaced using replaceWith() – Kraang Prime Aug 24 '15 at 00:09
  • 1
    `this` just got wiped out by replaceWith – charlietfl Aug 24 '15 at 00:10
  • @DavidThomas - it is about working with the new html after the replacement, upon replacement. I tried adding another 'this' loop after that, but it wouldn't working within the .fn. I have seen this method in use elsewhere for replacing controls and then delegating events to the transformed html, but not really finding anything at the moment on it hence why posting here. To Phil, that is a different issue which I can understand how you can jump to that without fully understanding what I am asking. – Kraang Prime Aug 24 '15 at 00:15
  • @charlietfl = see, you do not understand the problem. if that was the case, then `this` would no longer contain the old html, as it would contain the new html, and thus event registration would happen. `this` is (it seems) sort of readonly during the `.each`. – Kraang Prime Aug 24 '15 at 00:18
  • 1
    no...`this` is a reference to a dom element...when that element is removed so is the reference. replaceWith() creates a whole new element (or elements) in it's place – charlietfl Aug 24 '15 at 00:20
  • @charlietfl - I understand what `this` is. Updating that using `replaceWith` SHOULD change it and thus accessors to the new content are viable. If you like, I can demonstrate where after updating `this`, doing a dump of `this` reveals --- the ORIGINAL HTML. So why is it not taking when I try to register events on the new html, since it's already been updated ..... https://jsfiddle.net/rwsjLu3a/ >> shows that `this` is not changing. – Kraang Prime Aug 24 '15 at 00:25
  • well it is entirely possible that dom repaint and garbage collector hasn't completely wiped it out yet and if it hasn't then the html would still be different and we know it will be gone very shortly thereafter – charlietfl Aug 24 '15 at 00:28

2 Answers2

2

An alternative is to wrap the new html into a jQuery object and bind the handlers within that object

nHtml += '<div id="' + $(this).attr("id") + '">' + nHtml + '</div>';

var $html = $(nHtml);
$(this).replaceWith($html);

$html.find('span').click(function() {
    console.log($(this).text());
});
charlietfl
  • 170,828
  • 13
  • 121
  • 150
-2

this refers to the DOM element you just removed. Try using the id?

...
    var id = $(this).attr("id");

    $(this).replaceWith(nHtml);

    $('#'+id).find('span').click(function() {
         console.log($(this).text());
    });
...
raduation
  • 792
  • 5
  • 11
  • I am writing this as a jQuery extension, which means that it should do all that is required to replace AND handle events normally from within the function. The logical place to put this is during the loop, but after the html has been replaced. – Kraang Prime Aug 24 '15 at 00:16
  • So why can't you use the id? – raduation Aug 24 '15 at 00:25
  • 1
    @Sanuel Jackson what is the point of adding the id then if you can't use it? – charlietfl Aug 24 '15 at 00:32
  • You do understand how jQuery extensions work right ? You pass the id to the extension, then the object/object collection is stored in `this`, which is accessable through iteration. Using the `id` and raw one-off script like your example is good for one-off uses, but is not re-usable or convenient. Picture 200 elements on the page you need to do this to -- inconvenient to code, and bloated. The `id` also, is being unassigned from since – Kraang Prime Aug 24 '15 at 00:36
  • @SanuelJackson people are trying to help you....might help to drop the attitude down a bit – charlietfl Aug 24 '15 at 00:38
  • Why isn't my code reusable? It simply takes the id you just generated for the `div` and uses that. I don't understand why that is bloated. – raduation Aug 24 '15 at 00:41
  • @raduation I'm on your side, if the ID had never been created in the first place it would be a different story. I understand that ID's might make scaling a pain but if so it should have never been there in the first place – charlietfl Aug 24 '15 at 00:42
  • The id in html was there as a simple demonstration of a way to access the object, and a way for the user to define the name for the inner input field for form submissions to be natural. Where i started to get more frustrated was getting an XYZ answer to by ABC question. Im not really sure how I could have made the question more clear. The demonstration shows scalability in the jQuery function and is a really dumbed down version to demo the issue I am having. Additionally, the link to a non-related thread and the close() request was showing lack of attention to detail. – Kraang Prime Aug 24 '15 at 00:53
  • The issue was that during the foreach the `this` was not containing updated information. Accessing by `id` from inside a jQuery extension would make this a one-time use block of code specific to a specific id, and as you stated -- not scalable. I did not believe there would be a lack of understanding in this concept and as I try to give other solutions in good code practice, I do kind of expect the same in response. Admittedly, this is a bit of a hack anyway, but it doesn't mean that it needs to be locked down to one-time use, or incorporate techniques that lead to bloat. – Kraang Prime Aug 24 '15 at 00:56
  • I think it's poor form to personally attack someone trying to help you and downvoting a valid answer based on information you gave in your code, that you now say is a "dumbed down version" that is not representative of your real code. – raduation Aug 24 '15 at 01:00
  • @SanuelJackson you came here for help. You really need to get a grip of your attitude and should look a little closer in the mirror. You created the intiial ID. How are we supposed to read your mind as to what your intent is when you post that with no explanation of why it was there in the first place. People try to help and you go off the handle disrespecting their time and efforts attempt to help you. Things like that get rememebered – charlietfl Aug 24 '15 at 01:28
  • @charlietfl - `get a grip`, thats nice man. and you wonder why i respond in kind ? .... the problem wasn't with the HTML ... it was in the jQuery -- do you see anything ID specific in my jQuery example .... nope. so perhaps take a better look, and then see that there was clearly a comprehension issue here. My last response was fairly diplomatic, but you sir have just taken things to a whole other level with personal insults -- really --- and I am the immature one. Perhaps that mirror should be something you need to look into also -- and again "on your side" there were sides? grow up – Kraang Prime Aug 24 '15 at 01:56
  • @SanuelJackson There certainly is id specifc code in your example ...read what you wrote `'
    '`
    – charlietfl Aug 24 '15 at 01:58
  • Right, and that refers to specific one-off `id` usage. Totally. – Kraang Prime Aug 24 '15 at 01:59
  • And how would any of us know that when it's built into the plugin. You are a pompous ass ingrate .... get that snotty nose out of the air and come back down to earth – charlietfl Aug 24 '15 at 02:00
  • Huh ? ... why would I refer to an element dynamically that may or may not exist -- if I was intending to call by specific id by name? Second, again, why on earth would anyone hard code specific id's just to bypass an issue --- which in his above example doesn't work anyway. I appreciate your answer charlie, but this solution is way out in left field, as were several of the comments up to and including the link to a "duplicate". I know you see this as your answer using `$html = foo`, then calling `$html.foo()` works. It does pose another issue in event triggers but thats unrelated. – Kraang Prime Aug 24 '15 at 02:04
  • And to clarify -- at no point did i demonstrate or say -- my intention was to call specifically by hard coded `id`. If i dropped `class` or `custom-param`, that part is irrelevant to the problem which existed in the jQuery extension -- which is not a $(document).ready() code block. It is an extension. Syntax is the same, but night and day re distribution and coding styles. – Kraang Prime Aug 24 '15 at 02:05
  • I am also, not saying that his example is wrong -- it is just not suited for this purpose. It is good code given that there will always be an id param. Reading back on my comments here from the start, I do not see anything out of order, in fact, i further attempted to clarify, and understand the authors position in their response regarding knowledge on this topic. Possible my question could be rephrased -- i am not sure how, but I also don't dismiss the possibility for improvement -- but also possible, it was just simple confusion and getting hung up on a specific that is not relevant. – Kraang Prime Aug 24 '15 at 02:10