ASP.NET bootstrap modal display - asp.net

There is a representation in the form of a table. If I click on the row name in the table, a modal window is displayed. Modal window with a form that is quite complex.
To display the modal window I use the following code:
$('#modal-container').on('shown.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var url = button.attr("href");
var modal = $(this);
modal.find('.modal-content').load(url);
});
$.ajaxSetup({ cache: false });
$('#modal-container').on('hidden.bs.modal', function () {
$(this).removeData('modal');
});
There are the following problems:
when repeated calls for some very short time, the contents of the last call are displayed - it is not so important
sometimes new content is not displayed at all, and the modal window contains information from the last call - it's very important
tell me, please, what could be the problem. I do not know much about JS
code where content is downloaded:
<div id="modal-container" class="modal fade hidden-print" #*tabindex="-1" *# role="dialog" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog">
<div class="modal-content">
</div>
</div>
call from the action method
return PartialView("Details", projectECVM);
I suspect that the js runs faster than the razor generates the page.
Here I am forming a call for the action method:
#foreach (var item in Model.ProjectVM)
{
<tr class="clickableProject" id="#item.Id" title="View BugReports for #item.ProjectName">
<td id="Name">
<a id="details-link" asp-action="Details" asp-controller="Project" asp-route-id="#item.Id" title="View details project #item.ProjectName" data-toggle="modal" data-target="#modal-container">#Html.DisplayFor(it => item.ProjectName)</a>
</td>
<td id="Owner">
<label class="clickableProject">#item.Owner</label>
</td>
<td id="TrelloBoardURL">
<a id="trelloboard-link" href="#item.TrelloBoardURL" title="Go to TrelloBoard" target="_blank"><img src="~/images/trello-logo-blue.png" height="20" /></a>
</td>
<td id="Modification">
<label class="clickableProject">#item.Modification</label>
</td>
<td id="By">
<label class="clickableProject">#item.By</label>
</td>
<td id="DateTime">
<label class="clickableProject">#item.EntryDateTime</label>
</td>
</tr>
}

Clear the content of the dialog box before loading new content:
$(document).ready(function () {
$(function () {
$('#modal-container').on('shown.bs.modal', function (event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var url = button.attr("href");
var modal = $(this);
$(this).empty(); //adding this part before reloading it.
modal.find('.modal-content').load(url);
});
$.ajaxSetup({ cache: false });
$('#modal-container').on('hidden.bs.modal', function () {
//$(this).empty(); //moved from shown
$(this).removeData('modal');
});
if ($('#modal-container').text().trim().length > 0) {
$('#modal-container').dialog('open');
}
else {
}
});
});

Related

KnockoutJs : ko.mapping.fromJS and binding => how to do it properly?

I really am struggling with something that I thought was simple...
I am making a simple search-result table based on $.getJSON call, and want to keep my code as "generic" as possible.
In my (simplified) HTML :
<form id="searchForm">
(...)
<button type="button" onclick="search()">Search</button>
</form>
(...)
<tbody data-bind="foreach: data">
<tr>
<td data-bind="text: FOO"></td>
(...)
<td data-bind="text: BAR"></td>
</tr>
</tbody>
Then in my javascript (in script tags lower in the page):
var search = function(){
var form = $('#searchForm');
$.getJSON("php/query/jsonQuery.php?jsonQuery=search", form.serialize(), function(jsonAnswer, textStatus) {
console.log(jsonAnswer);
if(typeof viewModel === 'undefined'){
var viewModel = ko.mapping.fromJS(jsonAnswer);
ko.applyBindings(viewModel);
}
else{
ko.mapping.fromJS(jsonAnswer, viewModel);
}
$('#divResults').show();
// console.log(viewModel)
});
}
This works fine on the first "search" click... but not the following : Error You cannot apply bindings multiple times to the same element.
As you can guess, this very ugly "if" testing viewModel is a desperate attempt to get rid of that error.
I've tried many things but I just can't figure out how to do it properly...
I've read this Knockout JS update view from json model and this KnockoutJs v2.3.0 : Error You cannot apply bindings multiple times to the same element but it didn't help me much... maybe because the search() function isn't called on load (and indeed shouldn't be).
Any KO master to give me a clue? Thanks in advance for your help!
This is how I would be approaching what you are trying to accomplish.
var searchService = {
search: function(form, vmData) {
//$.getJSON("php/query/jsonQuery.php?jsonQuery=search", form.serialize(), function(jsonAnswer, textStatus) {
var jsonAnswer = [{
FOO: "Item 1 Foo",
BAR: "Item 1 Bar"
}, {
FOO: "Item 2 Foo",
BAR: "Item 2 Bar"
}]
ko.mapping.fromJS(jsonAnswer, [], vmData);
//})
}
};
var PageViewModel = function() {
var self = this;
self.data = ko.observableArray();
self.hasResults = ko.pureComputed(function() {
return self.data().length > 0;
});
self.search = function() {
var form = $('#searchForm');
searchService.search(form, self.data);
};
};
ko.applyBindings(new PageViewModel());
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.min.js"></script>
<form id="searchForm">
<button type="button" data-bind="click:search">Search</button>
</form>
<div data-bind="visible: !hasResults()"><b>No Results</b></div>
<div data-bind="visible: hasResults">
<table class="table">
<thead>
<tr>
<td>FOO</td>
<td>BAR</td>
</tr>
</thead>
<tbody data-bind="foreach: data">
<tr>
<td data-bind="text: FOO"></td>
<td data-bind="text: BAR"></td>
</tr>
</tbody>
</table>
</div>
<br/>
<pre><code data-bind="text: ko.toJSON($root)"></code></pre>

How to pass ID to controller and use it to display data on modal

I have passed the UserID to the table as shown in the code:
View
#foreach (var user in Model.RIROUsers)
{
<tr>
<td class="text-center">#(user.FirstName + " " + user.LastName)</td>
<td>View Details</button>
</tr>
}
Modal
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-body">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="form-group col-md-4 col-md-offset-2">
<label for="">* Address</label>
<input type="text" class="form-control input-sm" value="">
<label for="">* Birthday</label>
<input type="text" class="form-control input-sm" value="">
<label for="">* Contact</label>
<input type="text" class="form-control input-sm" value="">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Controller
public ActionResult Index()
{
var vm = new RIROViewModel();
vm.RIROUsers = new List<ResourceViewModel>();
foreach (var user in db_RIRO.sp_GetAllRIRORoster())
{
vm.RIROUsers.Add(new ResourceViewModel()
{
EID = user.EID,
FirstName = user.FirstName,
LastName = user.LastName,
EmployeeType = user.EmployeeType,
ProjectName = user.ProjectName,
JobTitle = user.JobTitle,
Level = user.CareerLevel,
ACNRollOn = user.HireDate,
ManagerName = user.Manager,
LeadName = user.Supervisor,
UserID = user.UserID
});
}
return View(vm);
}
Now when I click View Details I want the details of the user to display on the modal. What would be the best approach on this? I'm thinking of creating another stored procedure to retrieve the User's details and display it on the modal. But how do I do this?
EDIT 1: Changed button to a href=~/Views/RIRO/id=#user.UserID
As Shyju said, use click DOM event to the anchor link to show modal popup. Here are the steps:
1) Put Url.Action with proper controller and action name into href attribute of anchor link, then assign a class name to help identify each link.
<a href="#Url.Action("Details", "User", new { id = user.UserID })"
class="btn btn-xs btn-primary details" data-toggle="modal"
data-target="#exampleModal" data-id="#user.UserID">View Details</a>
2) Handle click DOM event using JS which rather than opening a new window/tab in browser, it should open modal popup instead (by using jQuery.ajax(), jQuery.get() or jQuery.load()):
$('.details').click(function (ev) {
ev.preventDefault(); // this is required
// get target action
var action = $(this).attr('href');
$.get(action, function (data) {
$(this).find(".modal-body").html(data);
$('#exampleModal').modal('show');
});
});
// alternative way
$('.details').click(function (ev) {
ev.preventDefault(); // this is required
// get target action
var action = $(this).attr('href');
$('.modal-body').load(action, function () {
$('#exampleModal').modal('show');
});
});
3) Ensure that target action method returns partial view which will loaded to the modal popup.
public ActionResult Details(int id)
{
var vm = new RIROViewModel();
// do something to retrieve data from DB
return PartialView("_Details", vm);
}
References:
Implementing Bootstrap Modal Popup In MVC Application
How to get anchor text/href on click using jQuery?

MVC4-Refresh Issue:Same partial view called 3 times using foreach..loop

I am in a tricky situation,
Scenario- There are gadgets which are to be shown in mobile site.
2.One of the gadget is RSS which user can add multiple times for different topics like one for security, one for news, one for events.
3. So we have 1 partial view for RSS, but if the user has 2 RSS gadgets then the same partial view should load with different gadget name. Here the functionality is working fine using foreach loop.
#foreach (var rssFeed in Model.RSSFeedList)
{
<article class="bm2014_bigBoxWrap bm2014_bigBoxRSS bm2014_paginate">
<img src="~/Content/images/iconRefresh.png" width="20" height="20" alt="refresh icon" title="refresh icon">
<div class="bm2014_expColCtrl">
<h1 class="bm2014_bigBoxHdr">
<span class="bm2014_hiddenHdr"> </span>
<!-- for markup validation -->
#if (rssFeed.Channel.Name == "xyznews")
{
<span>#Html.Label(Labels.Title_xyz)</span>
}
else if(rssFeed.Channel.Category=="xyzRSSFeed")
{
<!--<span>#Html.Label(Labels.xyz) - #rssFeed.Channel.Title</span>-->
<span>#rssFeed.Channel.Title</span>
}
<span class="bm2014_expColBtn"><img src="~/Content/images/iconPlus.png" width="32" height="32" alt="expand collapse icon" title="expand collapse icon"></span>
</h1>
<div class="bm2014_expColContent bm2014_bellnetRSSWrapper" id="bm2014_divBellnetRSS">
#Html.Partial("~/Views/Shared/_RSS.cshtml", rssFeed)
</div>
</div>
</article>
}
<!-- RSS Panel end here -->
Problem is with refresh issue
if i hit the refresh button for selected gadget, it is by default taking only one RSS name and loading the content irrespective of different gadget selected.
partialview page code-
#model Models.RSSFeed
#{
Layout = null;
}
<script src="~/Scripts/jquery-1.8.2.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.multilevelpushmenu.js" type="text/javascript"></script>
<script src="~/Scripts/jquery-simple-pagination-plugin.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.dataTables.js" type="text/javascript"></script>
<script type="text/javascript">
/* scripts to load after the DOM gets ready */
$(function () {
offCanvasMenu(); // trigger Javascript controlled OFF canvas menu after AJAX refresh
$.ajaxSetup({ cache: false });
$("article.bm2014_bigBoxRSS #btnRefresh").on('click', function (event) {
var $rssGadgetID = $(this).parents("article.bm2014_paginate").find("div#bm2014_divBellnetRSS");
var $rssGadgetLdr = $rssGadgetID.find("div#bm2014_gadgetLoader");
ajaxLoaderHeightCtrl($rssGadgetID, $rssGadgetLdr);
// AJAX control
$.ajax({
url: '#Url.Action("RefreshBellnetRSS", "Home", new { feedName = Model.Channel.FeedName })',
contentType: 'application/html; charaset=utf-8',
type: 'GET',
dataType: 'html',
success: function (result) {
$rssGadgetLdr.fadeOut(100, function () {
$rssGadgetID.html(result);
var moveRSS = $("article.bm2014_bigBoxWrap").css("float");
if (moveRSS == "left") {
mQueryAJAX("portrait", $rssGadgetID);
}
else if (moveRSS == "none") {
if (window.matchMedia("(orientation: portrait)").matches) {
mQueryAJAX("portrait", $rssGadgetID);
}
if (window.matchMedia("(orientation: landscape)").matches) {
mQueryAJAX("portrait", $rssGadgetID);
}
}
hideTableHeader();
});
},
error: function (xhr, status) {
alert(status);
}
});
});
});
</script>
<div class="bm2014_gadgetLoader" id="bm2014_gadgetLoader" style="display: none;">
<img src='#Url.Content("~/Content/Images/loaderGadget.gif")' width="48" height="48" alt="ajax loader image" title="ajax loader image">
</div>
<div class="bm2014_strategyContent">
#if (Model.url != null)
{
<table>
<thead>
<th>dummy header - to be hidden</th>
</thead>
<tbody>
#foreach (var url in Model.url)
{
<tr>
<td>
#url.Name
</td>
</tr>
}
</tbody>
</table>
}
</div>
need help/suggestions
If I understand correctly, you need to have 3 refresh buttons for 3 RSS gadgets e.g. one for security, one for news, one for events.
In the current example, every time you call the code to apply click event, you replace the earlier event and the 'feedname' parameter in url for ajax call also gets updated.
$("article.bm2014_bigBoxRSS #btnRefresh").on('click', function (event) {
......
}
You need to be able to distinguish between the refresh buttons and pass correct parameters. One way is to use data-feedname attribute on your btnRefresh anchor tag (if using HTML5)

How to navigate to new page when click on submit button using `meteor js`

I need when click on submit or login button how to navigate to new page with same window using meteor js. please help me how to write.
when user submit the form page navigate to admindetails.html page .I am using router package and the html page and client code is below. My intention is after user login load another template in same window dynamically .Please help me.
Here is html page
<template name="body">
<div class="bgbody">
<div align="center">
<form id="login-form" action="/admindetails">
<table>
<p class="admin">Admin Login</p>
<tr>
<td><p for="username">Admin Name</p></td>
<td><input type="text" id="username" name="username" placeholder="UserName"></td>
</tr>
<tr>
<td><p for="password">Password</p></td>
<td><input type="password" id="pwd" name="password" placeholder="password"></td>
</tr>
<td></td><td><input class="btn btn-success" type="submit" value="Log In"></td>
</table>
</form>
</div>
</div>
</template>
Here is the Client code
if (Meteor.isClient)
{
Meteor.Router.add({
'/admindetails':'admindetails'
})
Template.body.events
({
'submit #login-form' : function (e,t)
{
/* template data, if any, is available in 'this'*/
if (typeof console !== 'undefined')
console.log("You pressed the button");
e.preventDefault();
/*retrieve the input field values*/
var email = t.find('#username').value
, password = t.find('#pwd').value;
console.log(email);
Meteor.loginWithPassword(email, password, function (err)
{
if (err)
{
console.log(err);
alert(err.reason);
Session.set("loginError", true);
}
else
{
console.log(" Login Success ");
Meteor.Router.to("/admindetails");
}
});
}
});
}
If you use the recommended Iron Router, you use the go method:
Router.go('/articles/example');
or:
Router.go('showArticle', {name: 'example'});
If you use the old Router, use:
Meteor.Router.to('/articles/example');
If you don't use any router, start right now. In the meantime, use the stone-age method:
window.location.href = '...';

Binding Issues with KnockoutJs and Breeze - Navigation Properties

My app is based on the HotTowel template so it includes Durandal, Knockout & Breeze. I have a page with 3 tables side by side. The first table has a list of "templates', the 2nd table shows "sections" for the selected "template" and the 3rd table shows "items" for the selected "section". The "sections" and "items" tables are collections accessed via navigation properties. I find that I get intermittent binding issues. The data in the "templates" table always shows correctly, however related "sections" and "items" sometimes show correctly and other times one of the other is not populated. It would seem to be a timing issue. My view model and view are below. Am I just going about all of this the wrong way?
define(['services/dataservice', 'services/logger', 'services/model'],
function (ds, logger, model) {
var templates = ko.observableArray();
var selectedTemplate = ko.observable();
var selectedSection = ko.observable();
var selectedItem = ko.observable();
var newTemplateTitle = ko.observable();
var newSectionTitle = ko.observable();
var newItemTitle = ko.observable();
function activate() {
newTemplateTitle('');
newSectionTitle('');
newItemTitle('');
logger.log('Templates view activated', null, 'templates', false);
return ds.getTemplatePartials(templates, false, false);//.then(succeeded);
//function succeeded() {
// var firstTemplate = templates()[0];
// setSelectedTemplate(firstTemplate);
//}
}
templates.subscribe(function() {
var firstTemplate = templates()[0];
setSelectedTemplate(firstTemplate);
});
var deactivate = function () {
templates([]);
};
function refresh() {
return ds.getTemplatePartials(templates, true, false);
}
var viewAttached = function (view) {
bindEventToList(view, '#template-list', setSelectedTemplate);
bindEventToList(view, '#section-list', setSelectedSection);
bindEventToList(view, '#item-list', setSelectedItem);
return true;
};
var addTemplate = function () {
var newTemplate = ds.createEntity(model.entityNames.document);
newTemplate.title(newTemplateTitle());
newTemplate.isTemplate(true);
newTemplate.organisation(ds.getCurrentOrganisation()());
return ds.saveChanges().then(saveSucceeded);
function saveSucceeded() {
templates.push(newTemplate);
templates.sort();
newTemplateTitle('');
}
};
var addSection = function () {
var newSection = ds.createEntity(model.entityNames.section);
newSection.title(newSectionTitle());
newSection.isTemplate(true);
newSection.document(selectedTemplate());
return ds.saveChanges().then(saveSucceeded);
function saveSucceeded() {
newSectionTitle('');
}
};
var addItem = function () {
var newItem = ds.createEntity(model.entityNames.item);
newItem.title(newItemTitle());
newItem.isTemplate(true);
newItem.section(selectedSection());
return ds.saveChanges().then(saveSucceeded);
function saveSucceeded() {
newItemTitle('');
}
};
var isTemplateSelected = function (template) {
if (template && selectedTemplate()) {
var thisId = ko.utils.unwrapObservable(selectedTemplate().id);
return ko.utils.unwrapObservable(template.id) == thisId;
}
return false;
};
var isSectionSelected = function (section) {
if (section && selectedSection()) {
var thisId = ko.utils.unwrapObservable(selectedSection().id);
return ko.utils.unwrapObservable(section.id) == thisId;
}
return false;
};
var isItemSelected = function(item) {
if (item && selectedItem()) {
var thisId = ko.utils.unwrapObservable(selectedItem().id);
return ko.utils.unwrapObservable(item.id) == thisId;
}
return false;
};
var vm = {
activate: activate,
deactivate: deactivate,
templates: templates,
//sections: sections,
//items: items,
selectedTemplate: selectedTemplate,
selectedSection: selectedSection,
selectedItem: selectedItem,
title: 'Template Maintenance',
refresh: refresh,
viewAttached: viewAttached,
addTemplate: addTemplate,
addSection: addSection,
addItem: addItem,
newTemplateTitle: newTemplateTitle,
newSectionTitle: newSectionTitle,
newItemTitle: newItemTitle,
isTemplateSelected: isTemplateSelected,
isSectionSelected: isSectionSelected,
isItemSelected: isItemSelected
};
return vm;
//#region internal methods
function setSelectedTemplate(data) {
if (data) {
selectedTemplate(data);
return selectedTemplate().entityAspect.loadNavigationProperty("sections").then(setFirstSectionSelected);
} else {
return false;
}
function setFirstSectionSelected() {
setSelectedSection(selectedTemplate().sections()[0]);
}
}
function setSelectedSection(data) {
if (data) {
selectedSection(data);
return selectedSection().entityAspect.loadNavigationProperty("items").then(setFirstItemSelected);
} else {
selectedSection();
selectedItem();
return false;
}
function setFirstItemSelected() {
setSelectedItem(selectedSection().items()[0]);
}
}
function setSelectedItem(data) {
if (data) {
selectedItem(data);
} else {
selectedItem();
}
}
function bindEventToList(rootSelector, selector, callback, eventName) {
var eName = eventName || 'click';
$(rootSelector).on(eName, selector, function () {
var item = ko.dataFor(this);
callback(item);
return false;
});
}
//#region
}
);
<section>
<div class="row-fluid">
<header class="span12">
<button class="btn btn-info pull-right push-down10" data-bind="click: refresh">
<i class="icon-refresh"></i> Refresh</button>
<h4 class="page-header" data-bind="text: title"></h4>
</header>
</div>
<div class="row-fluid">
<section class="span3">
<header class="input-append">
<input id="newTemplateName"
type="text"
data-bind="realTimeValue: newTemplateTitle"
placeholder="New template name"
class="input-medium" />
<button class="btn btn-info add-on" data-bind="click: addTemplate, disable: newTemplateTitle() === ''">
<i class="icon-plus"></i> Add</button>
</header>
<article>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>Templates</th>
</tr>
</thead>
<tbody>
<!-- ko foreach: templates -->
<tr id="template-list" data-bind="css: { 'selected': $root.isTemplateSelected($data) }">
<td data-bind="text: title" />
</tr>
<!-- /ko -->
</tbody>
</table>
<span>Count: <span data-bind="text: templates().length"></span></span>
</article>
</section>
<section class="span5">
<header class="input-append">
<input id="newSectionName"
type="text"
data-bind="realTimeValue: newSectionTitle"
placeholder="New section name"
class="input-medium" />
<button class="btn btn-info add-on" data-bind="click: addSection, disable: newSectionTitle() === ''">
<i class="icon-plus"></i> Add</button>
</header>
<article data-bind="if: selectedTemplate">
<table class="table table-striped table-bordered table-hover" >
<thead>
<tr>
<th data-bind="text: 'Sections for ' + selectedTemplate().title()"></th>
</tr>
</thead>
<tbody>
<!-- ko foreach: selectedTemplate().sections() -->
<tr id="section-list" data-bind="css: { 'selected': $root.isSectionSelected($data) }">
<td data-bind="text: title" />
</tr>
<!-- /ko -->
</tbody>
</table>
<span>Count: <span data-bind="text: selectedTemplate().sections().length"></span></span>
</article>
</section>
<section class="span4">
<header class="input-append">
<input id="newItemName"
type="text"
data-bind="realTimeValue: newItemTitle"
placeholder="New item name"
class="input-medium" />
<button class="btn btn-info add-on" data-bind="click: addItem, disable: newItemTitle() === ''">
<i class="icon-plus"></i> Add</button>
</header>
<article data-bind="if: selectedSection">
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th data-bind="text: 'Items for ' + selectedSection().title()"></th>
</tr>
</thead>
<tbody>
<!-- ko foreach: selectedSection().items() -->
<tr id="item-list" data-bind="css: { 'selected': $root.isItemSelected($data) }">
<td data-bind="text: title" />
</tr>
<!-- /ko -->
</tbody>
</table>
<span>Count: <span data-bind="text: selectedSection().items().length"></span></span>
</article>
</section>
</div>
Similar issue (same server, same client but sometimes some navigators not working in breeze) happened to me. In my opinion it can be a timing bug. Or the create/load order of entities count.
I've changed this paralell async load entities from server:
return promise = Q.all([
getPackage(),
getClubPartials(null, true),
getAddressPartials(null, true),
getEventPartials(null, true)
]).then(success);
to this get them one by one:
return getClubPartials(null, true).then(function () {
getAddressPartials(null, true).then(function () {
getEventPartials(null, true).then(function () {
return getPackage().then(success);
})
})
});
And my problem gone!
There is just a lot of code to wade through and try to make sense of in the imagination.
You seem to say it works some of the time. That does sound like a timing issue.
One thing that is disturbing is the async methods (e.g. setSelectedTemplate) that return either false or a promise; not sure why the inconsistency. But that is probably not the real problem.
You could try putting a setTimeout(..., 10) before exiting the async methods. See if that changes the behavior.
If that doesn't reveal it, you'll have to boil it down to just those the essentials that reveal the problem.
Sadly no sudden flash of insight today.
Update June 3
My first concern is that some of your methods return promises and some return the value false. I'd feel more comfortable if they all returned promises. Look at Q.resolve().
Other code baffles me. For example, what is going on in the many variations on this pattern:
function setSelectedItem(data) {
if (data) {
selectedItem(data);
} else {
selectedItem();
}
}
The else{...} isn't doing anything useful. It unwraps the selectedItem property ... and discards the value. What is the point?
And what is the difference between this:
thisId = ko.utils.unwrapObservable(selectedTemplate().id); // obscure
and this?
thisId = selectedTemplate().id(); // clear
Are you unsure whether selectedTemplate().id is a KO observable? The only reason to use unwrapObservable is when you are unsure.
As for timing, you can let KO know that it should re-fresh a binding by calling valueHasMutated() on an observable. For example:
function setFirstItemSelected() {
setSelectedItem(selectedSection().items()[0]);
selectedItem.valueHasMutated();
}
It might help. I don't know ... you're stacking a long chain of dependencies and it isn't easy to see which are bailing out when. That would take study of actual data flows as well as the code. You cannot reasonably expect your StackOverflow audience to work that hard for free.
Try cutting this way down to a super-simple example that displays the troublesome behavior.
Best of luck.

Resources