0

I wrote my own Jquery month picker control. The month picker sits inside a <div />, which should in turn be attach to the <input /> field I call it upon.

To clarify, here is code:

(function ($) {
    //dict has to be a serialized dictionary. The dictionary needs to have years (as numbers) as keys and for each year a list of numbers representing the months.
    //Only the provided years/month will be serialized as html.
    //Sample usage (Razor): 
    //var json = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.Periods.ToArray())); 
    //$('#monthPicker').CondatoMonthPicker(json);
    $.fn.CustomMonthPicker = function (dict) {
        debugger;
        //Construct HTML
        var wrapper = $(this);

        $monthPickerHeaderHtml = $('some html...');
        wrapper.append($monthPickerHeaderHtml);
        };
})(jQuery);

As you notice from my code, I am using MVC Razor. Thus, I use this to instantiate the field holding the datepicker:

@Html.TextBoxFor(model => model.TimePeriod, new { @id = "custom-datepicker", @type = "date", @class = "ms-TextField-field" })     

However, this generates the following html:

<input autocomplete="off" class="ms-TextField-field" data-val="true" data-val-date="The field TimePeriod must be a date." data-val-required="The TimePeriod field is required." id="custom-datepicker" name="TimePeriod" type="date"> 

Notice the missing end tag. Going back to my custom date picker function, when I use .append() on my wrapper (<div />) object, it spits out the following ouput html:

<input autocomplete="off" class="ms-TextField-field" data-val="true" data-val-date="The field TimePeriod must be a date." data-val-required="The TimePeriod field is required." id="custom-datepicker" name="TimePeriod" type="date">
    My custom html goes here...
</input>

As you can see, instead of appending my custom html, it actually inserts it and adds an ending </input> tag after it, thus preventing my whole construct from showing on my page. Does anybody know why this is happening and how to work around

EDIT: I think I wasn't clear enough with my phrasing. I don't want to set the value of my <input> field. Somehow, JQuery gets the input element, INSERTS my html and adds a ending tag at then end when it should really add an end tag first and THEN append my custom html after that ending tag so it looks like this:

<input ...></input>
My custom html...
LeonidasFett
  • 3,052
  • 4
  • 46
  • 76
  • 1
    Please refer to the [`input` specification](https://www.w3.org/TR/html5/forms.html#the-input-element). `input` tags are not allowed to have a closing tag (even a short closing tag like `` is technically incorrect except in XHTML). You also cannot embed elements within an `input` tag (but you can a ` – Jared Farrish Mar 21 '16 at 22:14
  • Also, please make a working http://jsfiddle.net example that demonstrates your issue (in case we misunderstand). – Jared Farrish Mar 21 '16 at 22:16
  • 1
    To your edit: `input` elements have no end tags in HTML. Full stop. Here is [Chrome's representation of an `$.append()` operation](https://jsfiddle.net/qj07su51/): `
    This is to be appended.
    `. No closing tag as Chrome represents it. If you're not seeing this, you need to make a minimally viable example that demonstrates the problem so it can be reviewed in detail. I suspect, though, that your ASP (or whatever it is) code is doing it. You should probably add the appropriate tag to the question for that as well.
    – Jared Farrish Mar 21 '16 at 22:22
  • 1
    Here it is: https://jsfiddle.net/qj07su51/1/ Your `this` (and thus, `wrapper`) is referring to the `input` instead of the `div` you think it is. You can either select up with jQuery (`$.closest()` or `$.parent()`), or modify the plugin to get the parent first. Or use [`$.after()`](https://jsfiddle.net/qj07su51/2/) – Jared Farrish Mar 21 '16 at 22:28
  • Ok you beat me to it with your jsfiddle. $.after() did exactly what I wanted. Although I still don't know why append didn't actually append it to the end of my input and instead inserted it. Is it because my browser didn't see a ending tag and thus made it's own, thus changing my whole html structure? – LeonidasFett Mar 21 '16 at 22:32
  • 1
    It's because `$.append()` uses the current element and *adds* elements to it; it's not going to guess "no ending tag, let me add *after* the element instead". What you're seeing is a *representation* of the DOM that the browser makes, it should only be used as a guide. In this case, the browser sees a non-text node child and adds a closing tag to visual it's "within" that tag. But really, all it is is a child of the `input` node (which is doable with DOM methods but ill-advised). – Jared Farrish Mar 21 '16 at 22:35
  • thanks, I get it now. basically, append() just adds something to the end of something else? so if I had an ending tag, it would work, but without an ending tag, it wouldn't? – LeonidasFett Mar 21 '16 at 22:38
  • Example using DOM methods: https://jsfiddle.net/cfovsf4v/ – Jared Farrish Mar 21 '16 at 22:40
  • No, append takes the node and *within that node* adds another node, at the *end of that node's children*. The difference between jQuery's `$.append()` and `$.after()` is that `$.append()` first goes *into* that element, and adds a node to the end of the list, whereas `$.after()` will take that node's position with it's siblings and adds a node at the next position, moving the other nodes down one. – Jared Farrish Mar 21 '16 at 22:42
  • Similarly, `$.prepend()` and `$.before()` do the same, only they look first within the latter (adds a node at the first child position, shifting all other children down), and `$.before()` adds a node in the child position of it's parent so it's *before* the operating node and shifts all others down (including the node you're operating *on*). – Jared Farrish Mar 21 '16 at 22:44

1 Answers1

0

typically inputs do not have a closing tag and instead use the value attribute. what happens when you instead of appending, change the val() of the input. Text area would be more suited to having the opening and closing with an area for the input if that is what you need.

wrapper.val($monthPickerHeaderHtml);

here is a related article i found: closing HTML input tag issue

Community
  • 1
  • 1
TylerT
  • 69
  • 6
  • I think you misunderstood my question, I don't want to set the value of my input html field, I want to append my custom html after it. but somehow, jquery inserts it because it can't find a ending input tag when it should instead add a ending tag first and then append my html after that ending tag. – LeonidasFett Mar 21 '16 at 22:13
  • True, I did misunderstand but i think that the question is answered by understanding void elements. http://w3c.github.io/html-reference/syntax.html#void-element – TylerT Mar 21 '16 at 22:26