I'm trying to make knockoutjs and bootstrap modals play together by creating a custom bindingHandler in knockout, but for some reason the bindingHandler init & update functions never fire (i added prints to verify if this runs, which confirms it doesn't)
Here's my bindingHandler declaration:
require(['jquery', 'knockout', 'restaurant/ViewModel', 'bootstrap'], function ($, ko, ViewModel) {
console.log('running require');
ko.bindingHandlers.modal = {
init: function (element, valueAccessor) {
console.log('initializing bootstrap modal');
$('#restaurant-new-modal').modal();
},
update: function (element, valueAccessor) {
console.log('unwrapped valueAccessor:' + ko.unwrap(valueAccessor()));
if (ko.unwrap(valueAccessor())) {
$('#restaurant-new-modal').modal('show');
$('input#restaurant-new-name').focus();
}
else {
$('#restaurant-new-modal').modal('hide');
}
}
};
var viewModel = new ViewModel();
$.ajax({
url: 'http://localhost:8000/api/restaurants'
}).done(function (data) {
console.log('ajax query done');
for (var i = 0; i < data.length; i++) {
viewModel.addRestaurantToList(data[i]);
}
}).fail(function () {
console.log('AJAX query failed');
});
console.log('comes after ajax');
ko.applyBindings(viewModel, $('#restaurant-list-wrapper')[0]);
});
And my html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Restaurants</title>
<link type="text/css" rel="stylesheet" href="/lib/bootstrap/css/bootstrap.min.css"/>
<link type="text/css" rel="stylesheet" href="/css/style.css"/>
<script data-main="/js/restaurant/main" src="/lib/requirejs/require.js" type="application/javascript"></script>
</head>
<body>
<h1>Restaurants You Might Like</h1>
<div id="restaurant-list-wrapper" style="display: none;" data-bind="visible: restaurantList().length > 0">
<ul id="restaurant-list" data-bind="foreach: restaurantList">
<li class="restaurant">
<div class="restaurant-info">
<span data-bind="text: 'Restaurant #' + $data.store.id() + ': '"></span>
<a href="#" data-bind="text: $data.store.name, visible: !isEditable()"></a>
<input class="restaurant-input" type="text"
data-bind="visible: isEditable(), textInput: $data.tempName"/>
</div>
<div class="restaurant-action-bar">
<a href="#" class="restaurant-update-button btn btn-success btn-sm"
data-bind="text: 'Update', visible: isEditable(), click: $root.updateHandler"></a>
<a href="#" class="restaurant-edit-button btn btn-primary btn-sm"
data-bind="text: isEditable() ? 'Cancel' : 'Edit', click: $root.editHandler"></a>
<a href="#" class="restaurant-delete-button btn btn-danger btn-sm"
data-bind="text: 'Delete', click: $root.deleteHandler"></a>
</div>
</li>
</ul>
<div id="vertical-toolbar">
<a href="#" id="restaurant-new-button" class="glyphicon glyphicon-plus round green" data-bind="click: function() { showModal(true); }"></a>
</div>
</div>
<div id="restaurant-new-modal" class="modal fade" role="dialog" data-bind="modal: showModal">
<div class="modal-dialog modal-lg">
<div class="modal-header">
<h3 class="modal-title">Create New Restaurant</h3>
</div>
<div class="modal-content">
<ul>
<li>
<label for="restaurant-new-name">Enter new restaurant name</label><input id="restaurant-new-name"
type="text"/>
<a href="#" class="btn btn-success btn-lg" data-bind="click: newHandler">Create</a>
</li>
</ul>
</div>
<div class="modal-footer">
</div>
</div>
</div>
</body>
</html>
Any ideas?
You're applying bindings to #restaurant-list-wrapper
but your modal
binding is not inside it. You should also apply bindings to #restaurant-new-modal
(you can apply the same view model twice to different containers or wrap both containers into another one and apply binding to it only).