Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Mobile and Knockout.js templating, styling isnt applied

Ok so this is beginning to drive me insane. I have for several hours now searched and searched, and every single solution doesnt work for me. So yes, this question might be redundant, but i cant for the life of me get solutions to work.

I have a bunch of checkboxes being generated by a jquery template that is databound via knockout.js. However, it turns up unstyled. Afaik, it is something about jquery mobile does the styling before knockout renderes the template, so it ends up unstyled. I have tried numerous methods to no avail, so i hope someone here can see what i am doing wrong.

(i am using jquery mobile 1.2.0 , jquery 1.8.2 and knockout 2.2.1)

This is the scripts:

<script type="text/javascript">    


jQuery.support.cors = true;

var dataFromServer = "";    
// create ViewModel with Geography, name, email, frequency and jobtype
var ViewModel = {
  email: ko.observable(""),
  geographyList: ["Hovedstaden","Sjælland","Fyn + øer","Nordjylland","Midtjylland","Sønderjylland" ],
  selectedGeographies: ko.observableArray(dataFromServer.split(",")),
  frequencySelection: ko.observable("frequency"),
  jobTypes: ["Kontor (administration, sekretær og reception)","Jura","HR, Ledelse, strategi og udvikling","Marketing, kommunikation og PR","Handel og service (butik, service, værtinde og piccoline)","IT","Grafik og design","Lager, chauffør, bud mv.","Økonomi, regnskab og finans","Kundeservice, telefoninterview, salg og telemarketing","Sprog","Øvrige jobtyper"],
  selectedJobTypes: ko.observableArray(dataFromServer.split(",")),
  workTimes: ["Fulltid","Deltid"],
  selectedWorkTimes: ko.observableArray(dataFromServer.split(","))
};

// function for returning checkbox selection as comma separated list
ViewModel.selectedJobTypesDelimited = ko.dependentObservable(function () {
    return this.selectedJobTypes().join(",");
}, ViewModel);

var API_URL = "/webapi/api/Subscriptions/";

// function used for parsing json message before sent  
function omitKeys(obj, keys) {
  var dup = {};
  var key;
  for (key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (keys.indexOf(key) === -1) {
      dup[key] = obj[key];
      }
    }
  }
  return dup;
}

//Function called for inserting new subscription record
function subscribe() {
  if($("#jobmailForm").valid()=== true){
    //window.alert("add subscriptiooncalled");
    var mySubscription = ko.toJS(ViewModel);
    //var json = JSON.stringify(mySubscription);
    var jsonSmall = JSON.stringify(omitKeys(mySubscription, ['geographyList','jobTypes','selectedJobTypesDelimited','workTimes']));
    //window.alert(jsonSmall);
    $.ajax({
        url: API_URL,
        cache: false,
        type: 'POST',
        contentType: 'application/json',
        data: jsonSmall,
        success: function (data) {
          window.alert("success");

        },
        error: function (error) {
          window.alert("ERROR STATUS: " + error.status + "  STATUS TEXT: " + error.statusText);

        }
    });
  }
}

function initializeViewModel() {
  // Get the post from the API       
  var self = this; //Declare observable which will be bind with UI
  // Activates knockout.js
  ko.applyBindings(ViewModel);
}

// Handle the DOM Ready (Finished Rendering the DOM)
$("#jobmail").live("pageinit", function() {
  initializeViewModel();
  $('#jobmailDiv').trigger('updatelayout');
});


</script>
  <script id="geographyTmpl" type="text/html">
    <input type="checkbox" data-role="none" data-bind="attr: { value: $data }, attr: { id: $data }, checked: $root.selectedGeographies" />
    <label data-bind="attr: { for: $data }"><span data-bind="text: $data"></span></label>
  </script>
  <script id="jobTypeTmpl" type="text/html">
    <label><input type="checkbox" data-role="none" data-bind="attr: { value: $data }, checked: $root.selectedJobTypes" /><span data-bind="text: $data"></span></label>
  </script>

Note, "jobmail" is the surrounding "page" div element, not shown here. And this is the markup:

<div data-role="content">
<umbraco:Item field="bodyText" runat="server"></umbraco:Item>
<form id="jobmailForm" runat="server" data-ajax="false">
  <div id="jobmailDiv">
  <p>
    <label for="email">Email</label>
    <input type="text" name="email" id="email" class="required email" data-bind="'value': email" />
  </p>

  <fieldset data-role="controlgroup" data-mini="true" data-bind="template: { name: 'geographyTmpl', foreach: geographyList,  templateOptions: { selections: selectedGeographies } }">
    <input type="checkbox" id="lol"  />
    <label for="lol">fkfkufk</label>
  </fieldset>
  <fieldset data-role="controlgroup" data-mini="true">
    <p data-bind="template: { name: 'jobTypeTmpl', foreach: jobTypes,  templateOptions: { selections: selectedJobTypes } }"></p>
  </fieldset>

  <fieldset data-role="controlgroup" data-mini="true">
    <input type="radio" id="frequency5" name="frequency" value="5" data-bind="checked: frequencySelection" /><label for="frequency5">Højst 5 gange om ugen</label>
    <input type="radio" id="frequency3" name="frequency" value="3" data-bind="checked: frequencySelection" /><label for="frequency3">Højst 3 gange om ugen</label>
    <input type="radio" id="frequency1" name="frequency" value="1" data-bind="checked: frequencySelection" /><label for="frequency1">Højst 1 gang om ugen</label>
  </fieldset>

  <p>
  <input type="button" value="Tilmeld" class="nice small radius action button" onClick="subscribe();">
  </p>

  <a href="{locallink:1733}" data-role="button" data-icon="back" data-inline="true" data-direction="reverse">Tilbage</a>
</div>
</form>

Alternate method of invoking the restyling (doesnt work either):

$(document).on('pagebeforeshow', '#jobmail', function(){    
// Get the post from the API       
  var self = this; //Declare observable which will be bind with UI
  // Activates knockout.js
  ko.applyBindings(ViewModel);
});
// Handle the DOM Ready (Finished Rendering the DOM)
$("#jobmail").live("pageinit", function() {
  $('#jobmail').trigger('pagecreate');
});
like image 850
Frederik T Avatar asked Mar 04 '13 15:03

Frederik T


1 Answers

Use a custom binding (Knockout) to trigger jQuery Mobile to enhance the dynamically created content produced by Knockout.

Here is a simple custom binding:

ko.bindingHandlers.jqmEnhance = {
    update: function (element, valueAccessor) {
        // Get jQuery Mobile to enhance elements within this element
        $(element).trigger("create");
    }
};

Use the custom binding in your HTML like this, where myValue is the part of your view model that changes, triggering the dynamic content to be inserted into the DOM:

   <div data-bind="jqmEnhance: myValue">
      <span data-bind="text: someProperty"></span>
      <a href="#some-id" data-role="button">My Button</a>
      <input type="radio" id="my-id" name="my-name" value="1" data-bind="checked: someOtherProperty" /><label for="my-id">My Label</label>
   </div>

In my own case, myValue was part of an expression in an if binding, which would trigger content to be added to the DOM.

    <!-- ko if: myValue -->
    <span data-bind="jqmEnhance: myValue">
        <!-- My content with data-bind attributes -->
    </span>
    <!-- /ko -->
like image 200
John Mills Avatar answered Nov 30 '22 10:11

John Mills