1
votes

I'm trying to make a popover which has a html-form and a button with type "submit". This popover is also bound to knockout.js.

When I click the button on the popover, it does not trigger the KO function, instead it makes a standard post request.

If I move my form to outside of the popover, it works fine.

How can I create a html-form in a popover and trigger a function of my model with submit button?

Here is a non-working fiddle

<a href="#" id="createTaskPopover" data-toggle="popover" data-placement="right" title="Create Task">Click me!!!</a>

<div id="createTaskPopoverContent" class="hide">
    <form data-bind="submit: AddTask">
        <input type="hidden" id="FeatureId" name="FeatureId" value="" />
        <span>Name</span>
        <input type="text" id="Name" name="Name" style="width:100%;" /><br />

        <br />
        <button id="btnCreateNewTask" type="submit" class="btn btn-info">Create</button>
        <br />
    </form>
</div>
$('#createTaskPopover').popover({
        container: 'body',
        html: 'true',
        content: function () {
            return $("#createTaskPopoverContent").html();
        }
    });

function VM() {
    var self = this;
    self.AddTask = function (formElement) {
        console.log(formElement);
    }
}
var projectVM = new VM();
ko.applyBindings(projectVM);
2
You may be interested to look at knockstrap which helps bridge the gap between Bootstrap and Knockout. It's got a specific binding for popovers. - James Thorpe
I think, there should be a way, without using any extension. It is not a rare problem I have faced. - ahmet
Oh yes - it's certainly not an answer to your question, but it's handy to know these things exist sometimes :) Looking at your specific problem, I think it's because you're dynamically returning the content of the popup using .html(), so it's losing the submit binding at that point. I don't have a workaround as yet though... - James Thorpe

2 Answers

2
votes

The reason it's not working is because you're duplicating the html with the .html() call, at which point the knockout bindings are lost. You can actually give bootstrap the element to use directly, and coupled with the shown event to remove the hide class, it works as you want it to:

$('#createTaskPopover').popover({
    container: 'body',
    html: 'true',
    content: $("#createTaskPopoverContent") //return element directly
}).on('shown.bs.popover', function() {
    $('#createTaskPopoverContent').removeClass('hide'); //remove hide when popover shown
});

Here's an updated fiddle. Note however that you see a slight flicker when the popover opens while it "unhides" the content.

This can be further improved by passing just the inner form (or you could wrap it in another div if you want) to the popover, and then you don't even need to handle the shown event, and you don't see the content "appearing" once the popover has shown:

$('#createTaskPopover').popover({
    container: 'body',
    html: 'true',
    content: $("#createTaskPopoverContent > form") //select the form directly
});

Further updated fiddle.

0
votes

The reason the function isn't triggered is because the HTML the popover uses is injected at runtime and Knockout bindings have been applied already:

content: function () {
           return $("#createTaskPopoverContent").html();
         }

Option A: Do Knockout binding once the popover has shown

$('#createTaskPopover').on('shown.bs.popover', function () {
  var projectVM = new VM();
  ko.applyBindings(projectVM);
})

Option B: Inline the HTML and simplify to $('#createTaskPopover').popover()

data-content="raw HTML here" data-html="true"