7

When I am navigate to details page to second time,page becomes naked,all styles vanish from the page,I could figure out the reason, example http://jsfiddle.net/Hpyca/24/

Html

<div data-role="page" id="dashBoardPage" data-bind="with: dashboardData">
   <button type="button" data-bind="click: goToList">DashBoard!</button>
</div>
<div data-role="page" id="firstPage" data-bind="with: hospitalList">
   <div>
      <div id="listViewDiv">
         <ul data-role="listview" data-bind="foreach: hospitals">
            <li data-bind="click: $parent.selectHospital">
               <h2>Hospital Id:<span data-bind="text:id"></span></h2>
               <p>Name <span data-bind="text:name"></span></p>
            </li>
         </ul>
      </div>
   </div>
</div>
<div data-role="page" id="detailsView" data-bind="with: hospitalList.selectedHospital">
   <a href="#firstPage">Back</a>
   <a href="#dashBoardPage">Home</a>
   <div>
      <div data-role="tabs" id="tabs">
         <div data-role="navbar">
            <ul>
               <li><a href="#one" data-ajax="false">Info</a></li>
               <li><a href="#two" data-ajax="false">Details</a></li>
            </ul>
         </div>
         <div id="one" class="ui-body-d ui-content">
            <h2>Hospital Id : <span data-bind="text:id"></span></h2>
         </div>
         <div id="two">
            <h2>Id : <span data-bind="text:id"></span></h2>
            <input data-mini="true" tabindex="5" data-bind="value: name"
               id="name"/>
         </div>
      </div>
   </div>
</div>

js

function NavigationService(){
    var self = this;

    self.navigateTo = function(pageId){
        $.mobile.changePage($('#' + pageId));
    };
}
//You need to determine if you want to handle dependencies using requirejs or just global variables.
var navigationService = new NavigationService();

function HospitalViewModel(data){
    var self = this;
    self.id = data.id;
    self.name = ko.observable(data.name);
}

function DashboardViewModel(data){
    var self = this;

    self.goToList = function(){
        navigationService.navigateTo('firstPage');
    };
}

function HospitalListViewModel(data){
    var self = this;

    self.hospitals = data;
    self.selectedHospital = ko.observable();

    self.selectHospital = function(hospital){
        self.selectedHospital(hospital);
        navigationService.navigateTo('detailsView');
    };
}

function PageViewModel(){
    var self = this;

    //This list should be retrieved from a service of some kind
    var allHospitals = [
        {"id":"001","name":"Hospital1","location":"SL"},
        {"id":"002","name":"Hospital2","location":"SL"}
    ].map(function(hospital){return new HospitalViewModel(hospital);});

    self.hospitalList = new HospitalListViewModel(allHospitals);
    self.dashboardData = new DashboardViewModel();
}

ko.applyBindings(new PageViewModel());

To reproduce the issue , Click(DashBoard) --> Click(ListElement) --> Click(Back,Home) --> Click(again list element --> go to details page),now you can see the naked UI,

ExCode
  • 444
  • 2
  • 9
  • 24

2 Answers2

4

The problem is coming from the KnockoutJS "with:" statement.

My guess is that the "with:" turns a weird property "visible" or "display" to false when the ko.observable is empty, and then Jquery (mobile) trying to use the property to apply style, fails to find the DOM item with its selector. The crazy thing being that I did not find any source documenting the issue?

I experimented similar problem with some Jquery plugins before (datepicker, masked inputs...), the solution I found was re-apply Jquery plugin after binding the observable.

Unfortunately, this "hack" is not useful in your case as Jquery Mobile is not manually applied via JavaScript. I looked for some way "to refresh" Jquery Mobile but no result.

So I came up with a solution by removing "with:" statement, calling the full property name and binding an empty "hospital" in the observable to prevent null reference exception.

JsFiddle

<span data-bind="text:hospitalList.selectedHospital().id"></span>

self.selectedHospital = ko.observable({id:"",name:"",location:""});

This solution is far from ideal, and not really scalable. But, the other way would be inspecting the code of both libraries to identify the "conflict".

Hope it helps!

Yooz
  • 2,506
  • 21
  • 31
  • Yes this way also working for me,but how I could call a function within this object scope,I've update the http://jsfiddle.net/Hpyca/28/, Can I use knockout "template", instead of "with" – ExCode Apr 28 '14 at 11:30
  • @ExCode Yes, you could use a knockout template and call functions within the object scope; but it isn't (always) necessary. The first parameter in a handler function will contain the value of the current model. See [updated fiddle](http://jsfiddle.net/Hpyca/29/) (go to the details of a hospital). Does that help? – rwisch45 Apr 28 '14 at 15:55
  • @rwisch45 thank you for the response.in your updated code (http://jsfiddle.net/Hpyca/29/) css error still continues,I want to over come css issue.To reproduce the issue , Click(DashBoard) --> Click(ListElement) --> Click(Back,Home) --> Click(again list element --> go to details page),now you can see the naked UI, – ExCode Apr 29 '14 at 01:08
  • @ExCode I updated your fiddle (http://jsfiddle.net/Hpyca/31/). Just add data parameter in the function, which contains the full viewmodel, then you can lookup into it, get the selectedHospital and work with it. – Yooz Apr 29 '14 at 01:25
  • Thank you @Yoann,can't we use two template for same object?,In my real implementation I have 3 tabs – ExCode Apr 29 '14 at 08:19
  • Sorry, I am not sure about your last question? you can apply the selectedHospital scope to any "templates" that you want, "template" meaning HTML blocks. As said before, the KnockoutJS template system does not work well with JqMobile. – Yooz Apr 30 '14 at 00:29
2

Found the answer for you, and I've updated your original fiddle - it is now working as intended. The only change made was to your NavigationService as follows:

function NavigationService() {
    var self = this;

    self.navigateTo = function (pageId) {
        $.mobile.changePage($('#' + pageId));
        $('#detailsView').trigger('create'); // add this line
    };
}

There are a few other questions here on SO that address this:

Community
  • 1
  • 1
rwisch45
  • 3,692
  • 2
  • 25
  • 36