0

I am using the jQuery Steps plugin to create a wizard and on step two, you will add 1..* fields, which is an array of JSON objects that'll get posted to the server. I'm trying to use Knockout to show an input for each field name.

On click, a new empty field should get pushed to the array and a textbox should display. However, the addField function doesn't fire when inside the form/jquery steps. If I take it out, it does. Is there a way to prevent jQuery steps from interfering with the binding? Here's a condensed version of the code:

function AppViewModel() {
    var self = this;
    self.fields = ko.observableArray([]);
    self.addField = function() {
        // push field to self.fields
    }

}
ko.applyBindings(new AppViewModel());

// jQuery Steps
var form = $("#stepsForm");

form.children("div").steps({
    headerTag: "h3",
    bodyTag: "section",
    transitionEffect: "slideLeft",
    stepsOrientation: "vertical"
});
table {
  border: 1px solid blue;
}
td {
  border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-steps/1.1.0/jquery.steps.min.js"></script>
 
<form id="stepsForm" action="#" novalidate>
    <div class="form-container">
        <h3>Section1</h3>
        <section>
            <table class="table table-condensed">

                <tr data-bind="foreach: fields">
                    <td>
                        <div data-bind="text:FieldName"></div>test
                    </td>
                </tr>
            </table>

            <button data-bind="click: addField">Add another</button>

        </section>
    </div>
</form>
Elliott
  • 2,035
  • 20
  • 23
  • Do you use a "steps" custom binding handler? (Rhetorical question, I don't see you using one, but I think you should.) – Tomalak Mar 07 '16 at 15:43
  • No I don't. This is really my first crack and Knockout. Some other searches I did eluded to using a Custom Binding handler but after reading through the KO documentation on it I couldn't wrap my ahead around it enough to know if it was applicable to my situation – Elliott Mar 07 '16 at 15:47
  • 3
    I don't know jQuery-steps, but I know my way around Knockout pretty well. Usually you don't want to have a knockout app with a second library that does UI manipulation without a proper binding handler that connects it to knockout. – Tomalak Mar 07 '16 at 15:51
  • That said, after turning your code above into a runnable snippet, it seems to work - at least it adds something, I'm not sure if that's what is supposed to happen. – Tomalak Mar 07 '16 at 15:52
  • Indeed, your edits work. It makes me wonder if it's perhaps the order in which the libraries are referenced. I'll poke around and report back. Thanks – Elliott Mar 07 '16 at 15:53
  • jQuery-steps is not *used* in any way in the code above, so for the moment this is a run-off-the-mill Knockout app that adds table cells. You will need to detail how you plan to use the steps plugin, exactly. – Tomalak Mar 07 '16 at 16:01
  • Bah. Duh. Back to the drawing board. I'll include the Steps code above – Elliott Mar 07 '16 at 16:05
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/105582/discussion-between-elliott-and-tomalak). – Elliott Mar 07 '16 at 16:28

1 Answers1

0

This issue came down to the timing of JavaScript execution. It was complicated by the fact that I'm using server data to load Knockout objects (without ajax). This is where I finally netted:

My JavaScript loads in this order:

  1. jQuery, jQuery steps, Knockout, etc (bundled)
  2. JavaScript file for the view
  3. Inline JavaScript embedded in the view

#2 - JavaScript file for the view (e.g. fields.js)

$(document).ready(function () {

    var form = $('#stepsForm');

    form.children("div").steps({
        headerTag: "h3",
        bodyTag: "section",
        transitionEffect: "slideLeft",
        stepsOrientation: "vertical"
    });
});

#3 - Embedded JavaScript in the view (e.g. fields.html)

<script>
    function AppViewModel() {
        var self = this;
        self.fields = ko.observableArray([]); 
        self.addField = function () {
            // push field to self.fields
        }
    }
    $(document).ready(function () {
        //Used MVC Razor engine to load some other server data into other KO objects here. (omitted for clarity)
        ko.applyBindings(new AppViewModel());

    })

</script>
Elliott
  • 2,035
  • 20
  • 23