Set default value in SELECT after it has been re-loaded

1,866 views
Skip to first unread message

Renso

unread,
Jul 28, 2011, 7:15:44 PM7/28/11
to KnockoutJS
After my json object is retrieved from the server based on a record a
user selects on the screen, I update my KO viewModel and then since
one of the observableArrays (productTypeOptions) has been reloaded I
need to set it's default value to that of the appropriate value.
However, productTypeOptions consists of a collection of objects and
not string values, such as Id, Name, Product (an id value),
ProductType (also an unique Id of the product type), etc. So in order
to set the default value from the productTypeOptions dropdown list I
do the following without success. Note that I also loop through the
productTypeOptions to find the correct object and then try and set the
default value in ko.observableArray(item).
$.ajax({
data: { Id: rateCardId },
url: $('#ajaxGetRateCardDetailUrl').val(),
type: "GET",
dataType: "json",
success: function (result) {

ko.mapping.updateFromJS(crm.rateCard.administration.viewModel,
result);

crm.rateCard.administration.viewModel.selectedProductTypeId =
result.ProductType;

var prods = [];
//window.productTypes contains all product types, but
depending on what product is defaulted only that product's relevant
product types must be loaded
$.each(window.productTypes, function (index, value) {
if (value.Product ==
crm.rateCard.administration.viewModel.Product()) {
prods.push(value);
}
});


prods.sort(crm.rateCard.administration.sortProductTypeDetail);

//this.productTypeOptions.removeAll();
crm.rateCard.administration.viewModel.productTypeOptions =
ko.observableArray(prods);
var item = null;


ko.utils.arrayForEach(crm.rateCard.administration.viewModel.productTypeOptions(),
function (e) {
if (e.Id == result.ProductType) {
item = e;
}
return item;
});

crm.rateCard.administration.viewModel.selectedProductType
= ko.observable(item);
ko.applyBindings(crm.rateCard.administration.viewModel);

"result" contains my json string. I use the result.ProductType, which
is an identity key of type integer to find the exact default object
from the productTypeOptions list with:

ko.utils.arrayForEach(crm.rateCard.administration.viewModel.productTypeOptions(),
function (e) {
if (e.Id == result.ProductType) {
item = e;
}
return item;
});

So I am getting the object itself (I think).

In the following lines I try and set the default value (object) but to
no avail, it does not work:
crm.rateCard.administration.viewModel.selectedProductType
= ko.observable(item);
ko.applyBindings(crm.rateCard.administration.viewModel);

Here is what my viewmodel looks like:
crm.rateCard.administration.viewModel =
ko.mapping.fromJS(rateCard);
crm.rateCard.administration.viewModel.Year = ko.observable();
crm.rateCard.administration.viewModel.Version = ko.observable();
crm.rateCard.administration.viewModel.rateCardOperation =
ko.observable();
crm.rateCard.administration.viewModel.rateCardStatus =
ko.observable();
crm.rateCard.administration.viewModel.TotalContracts =
ko.observable();
crm.rateCard.administration.viewModel.TotalNonContractContracts =
ko.observable();
crm.rateCard.administration.viewModel.TotalContractContracts =
ko.observable();
crm.rateCard.administration.viewModel.allowSavingThisRateCard =
ko.observable('disabled');
crm.rateCard.administration.viewModel.Product = ko.observable();
crm.rateCard.administration.viewModel.productTypeOptions =
ko.observableArray(undefined)();
crm.rateCard.administration.viewModel.selectedProductType =
ko.observable();
crm.rateCard.administration.viewModel.selectedProductTypeId = 0;

Here is a piece of the relevant HTML:

<label for="Product" class="required">
Product :</label>
<%=Html.DataBoundSelectList("Product", new
SelectList(ViewData.Model.ProductList, "Id", "Name"), "select...", new
{ @class = "crm_editGroup" })%>
<br />

<label for="ProductType" class="required">
Product Type :</label>
<select id="ProductType" data-bind="options: productTypeOptions,
optionsCaption: '...', optionsText: 'Detail', optionsValue: 'Id',
value: selectedProductType"
class="XXXcrm_editGroup">
</select>
<span id="productTypeSelectionDetail" data-bind="text:
productTypeSelectionDetail">
</span><span data-bind="text: selectedProductType.Detail"></span>

rpn

unread,
Jul 29, 2011, 12:29:08 AM7/29/11
to knock...@googlegroups.com
Can you possibly throw this into a jsFiddle that shows the error?    

Renso

unread,
Jul 29, 2011, 8:49:31 AM7/29/11
to KnockoutJS
It is not throwing an error, it is just not setting the default value
of the drop down list at all.

In the following code I loop through my DOM object that contains all
my product types and only select the ones I want to load into the drop
down box:
$.each(window.productTypes, function (index, value) {
if (value.Product ==
crm.rateCard.administration.viewModel.Product()) {
prods.push(value);
}
});

prods.sort(crm.rateCard.administration.sortProductTypeDetail);

Then I init my observableArray with it:

crm.rateCard.administration.viewModel.productTypeOptions =
ko.observableArray(prods);
var item = null;

Now I am getting the object that I want to use to set the default
value in the drop down box:
ko.utils.arrayForEach(crm.rateCard.administration.viewModel.productTypeOptions(),
function (e) {
if (e.Id == result.ProductType) {
item = e;
}
return item;
});

And now I am init the default value in the drop down box, and this
part simply does not do what I expect it to do, it does nothing, I am
expecting the correct default value to be pre-selected in my drop down
box:

crm.rateCard.administration.viewModel.selectedProductType
= ko.observable(item);
ko.applyBindings(crm.rateCard.administration.viewModel);

I cannot believe that I am the only one that needs to init a drop down
box with a default value after it has been altered/reloaded. How hard
can it be? I am missing something obvious here?! Maybe in stead of
trying th do a mapping.updateJSON, I shoud new up my viewmodel
entirely, although even with that I still need to pre-select my
productTypeOptions' default value.

Just to help here a a snap shot of what one of the productTypeOptions
objects look like:
Commissionable true
CoverageFrom 1
CoverageTo 2
Description "StoreFront Package"
Detail "StoreFront Package (1 - 2)"
GenerateHowManyTrafficLineItems 0
Id 5
Listing false
Name "StoreFront Package"
Product 1

So when the json object comes back from the server I use
mapping.updateJSON to refresh my viewmodel, but recall I am also
completely re-loading the productTypeOptions observableArray with new
values. Here is what that json object from the server looks like:



Sort by key

Id "309"
Name "2010.001"
Year "2010"
Version "001"
Description "2010.001"
Product 3
ProductType 20
Online 4
Amount 4350
GrossAmountOverride false
EffectiveFrom "1/1/2010"
EffectiveTo "1/1/2011"
CoverageFromTo "(1 - 2)"
TotalContracts 0
TotalNonContractContracts 0
TotalContractContracts 0
Used "False"

I then look for the correct productType in window.productTypes to find
the object and using the json object's ProductType ("20" in this
example) to get the object and using that object to pre-select the
drop down list that productTypeOptions is bound to:
<select id="ProductType" data-bind="options:
productTypeOptions,optionsCaption: '...', optionsText: 'Detail',
optionsValue: 'Id',value: selectedProductType" >
</select>

I thought if I can pass in the object to

crm.rateCard.administration.viewModel.selectedProductType
= ko.observable(item);

,item being that object, that it should then select that option from
the drop down list, but it does not. Any clues of why this does not
work? Much appreciate any feedback. If anyone has an example of where
they are pre-selecting a value from a drop down box with a list of
objects, not simply types like strings, please paste it in here, no
need to taylor my example if it's easier to just share how to set a
default value for a drop down box AFTER the viewmodel has been
reloaded.

rpn

unread,
Jul 29, 2011, 8:55:11 AM7/29/11
to knock...@googlegroups.com
If you specify your select like this:

<select id="ProductType" data-bind="options: 
productTypeOptions,optionsCaption: '...', optionsText: 'Detail', 
optionsValue: 'Id',value: selectedProductType" > 
    </select> 


Since, your optionsValue is set to 'Id', the value of selectedProductType is expected to be the Id property of the object and not the object itself.  So, I believe that you want to set selectedProductType to the Id property of your item.

Did I understand what you are doing correctly?

Renso

unread,
Jul 29, 2011, 9:35:25 AM7/29/11
to KnockoutJS
Mo sire what happened to my previous reply, basically rpn, you are
absolutely correct, I forgot about the optionsValue. I now removed my
loop to search for the productTypeOptions object entriely, no need,
and just specify the ID from the json object from the server. Thank
you so much! Life saver, I was about to go back to my options
selectboxes plug-in.

Here is my final code:
$.ajax({
data: { Id: rateCardId },
url: $('#ajaxGetRateCardDetailUrl').val(),
type: "GET",
dataType: "json",
success: function (result) {

ko.mapping.updateFromJS(crm.rateCard.administration.viewModel,
result);

var prods = [];
$.each(window.productTypes, function (index, value) {
if (value.Product ==
crm.rateCard.administration.viewModel.Product()) {
prods.push(value);
}
});


prods.sort(crm.rateCard.administration.sortProductTypeDetail);


crm.rateCard.administration.viewModel.productTypeOptions.removeAll();
//load all the product types that are relevant to the
product
crm.rateCard.administration.viewModel.productTypeOptions =
ko.observableArray(prods);

//result.ProductType contains the ID
crm.rateCard.administration.viewModel.selectedProductType
= ko.observable(result.ProductType);
ko.applyBindings(crm.rateCard.administration.viewModel);


Thanks heaps rpn!

Renso

unread,
Aug 1, 2011, 4:42:39 PM8/1/11
to KnockoutJS
I thought I had it all figured out, but the applyBindings causes
events to be re-registered every time the JSON object is reloaded and
applyBindings called, but if you see the code below, I needed to do
the applyBindings again to "see" the newly loaded productTypes.

$.ajax({

data: { Id: rateCardId },

url: $('#ajaxGetRateCardDetailUrl').val(),

type: "GET",

dataType: "json",

success: function (result) {

ko.mapping.updateFromJS(crm.rateCard.administration.viewModel,
result);

crm.rateCard.administration.viewModel.selectedProductTypeId =
result.ProductType;

//find all the product types that are relevant to the product

var prods = [];

$.each(window.productTypes, function (index, value) {

if (value.Product == crm.rateCard.administration.viewModel.Product())
{

prods.push(value);

}

});

prods.sort(crm.rateCard.administration.sortProductTypeDetail);

crm.rateCard.administration.viewModel.productTypeOptions.removeAll();

//load all the product types that are relevant to the product

crm.rateCard.administration.viewModel.productTypeOptions =
ko.observableArray(prods);

var item = null;

//Search for the product types that I want to pre-select.

ko.utils.arrayForEach(crm.rateCard.administration.viewModel.productTypeOptions(),

function (e) {

//result is the json object that contains the ProductType that is the
unique ID of the product type

if (e.Id == result.ProductType) {

item = e;

}

return item;

});

//Now pre-select the product type - this does not pre-select the value
in the HTML SELECT tag - need to aplyBindings again

crm.rateCard.administration.viewModel.selectedProductType

= ko.observable(item);

//Now re-bind so it pre-selects the drop down box on the screen
itself.

//Unless I do this the bind to the drop down box is not there and
changes to the viewmodel has no affect on the HMTL controls.

//But the issue now is that all the events are registered again in
duplciate and of course everytime this funtion is called

//to reload the json applybindings adds the events again-and-again -
what is the solution to this issue??

ko.applyBindings(crm.rateCard.administration.viewModel);

},

error: function (xmlHttpRequest, textStatus, errorThrown) {

alert('An error occurred: ' + errorThrown);

}

}); //ajax

};

Renso

unread,
Aug 1, 2011, 4:51:03 PM8/1/11
to KnockoutJS
What if I just re-bind to the drop down box (productTypeOptions that
actually is reloaded with a new collection of objects:

ko.applyBindings(crm.rateCard.administration.viewModel, $
('#RateCardAdministrationWrapper #RateCardDetail #ProductType')[0]);

HTML:

<label for="ProductType" class="required">
Product Type :</label>
<select id="ProductType" data-bind="options: productTypeOptions,
optionsCaption: '...', optionsText: 'Detail', value:
selectedProductType"
class="crm_editGroup">
</select>

Seems to work and not -add duplicate events as when I re-bind all as
in (like I did before):

ko.applyBindings(crm.rateCard.administration.viewModel);

Is this the correct way to do this?
> //Nowpre-selectthe product type - this does notpre-selectthe value
> in the HTML SELECT tag - need to aplyBindings again
>
> crm.rateCard.administration.viewModel.selectedProductType
>
> = ko.observable(item);
>
> //Now re-bind so it pre-selects thedropdownbox on the screen
> itself.
>
> //Unless I do this the bind to thedropdownbox is not there and

rpn

unread,
Aug 1, 2011, 7:21:21 PM8/1/11
to knock...@googlegroups.com
Hello-
I have not digested all of your code, but maybe you could make a jsFiddle that shows it simplified.  

In my mind, there is really only one time that you should call applyBindings more than once.  That would be if you are dynamically loading HTML content that has not been previously managed by Knockout (so, not from template binding).  In that case, you can call ko.applyBindings(viewModel, element).  If you just want to apply bindings to the individual node and not its children, then you can call ko.applyBindingsToNode(element, null, viewModel);

If you are your select is bound to observables and you update those observables, then your UI should be updated with the new options or new selection.  

Hope this helps..  I would like to understand your issue and get it sorted out.


Reply all
Reply to author
Forward
0 new messages