0
votes

I am translating my model from the server using ko.mapping.fromJS(data, mapping) method, so that i can add more properties to my sub models.

following the example here: http://knockoutjs.com/documentation/plugins-mapping.html => "Customizing object construction using “create”

here is my code:

var Employer = function (data) { 
        ko.mapping.fromJS(data,{}, this); 
        this.Foo = ko.observable("bar"); // added properties will go here. 

        console.log(this.Foo());      // i see this getting called OK on initial creation, and subsequent creations
        console.log(this.Name()); // ** this is only OK during initial creation, but on subsequent times i get "[Object] does not have a property Name" this property comes from the server model..** 
        }; 

        var mapping = {     
            'Employers' : { 
                create: function (options) {
                     var e = new Employer(options.data);
                     return e;
                } 
            } 
        }; 

        model = ko.mapping.fromJS(data, mapping); 

so far this works ok!

the problem happens here:

        model.addEmployer = function (options, o2) {
            var e = new Employer(options);
             this.Resume.Employers.push(e);
        }; 

i am missing something here.. when i want to add a new object to the collection, it is missing all the properties that came from the model (from the server) which were added on with this line "ko.mapping.fromJS(data,{}, this); " inside the Employer constructor.

i am guessing i need to repeat some similar mapping inside the addEmployer function that will re-bind all server side properties to the client model

here is how i'm calling addEmployer:

 <button data-bind="click: addEmployer">...</button>

UPDATE

what it boils down to, is when declaring 'create' event in the mapping, that function receives options object, which has options.data which can be used in this call: ko.mapping.fromJS(data,{}, this); .. i am not sure how to get this type of object in my addEmployer handler, to provide necessary bindings for all the properties that exist on Employer object on the servier.

i can sort of hack it by preserving that options.data from initial binding, and re-using that in the addEmployer handler. the problem with that, is it will have all the properties set from that initial object.

what i basically need, is EmployerMappingOptions object that is empty. in the above implementation, options.data comes pre-populated with data on the first Employer object in my collection. how can i get that mapping data for empty Employer model?

2
It is correct that you are passing this as destination for the mapping transformation inside the addEmployer method? Perhaps you wanted to load data into the new employer e? - Grim
@Grim yep, i've tried a few approaches here.. i'll update my question with it. - Sonic Soul
WHy are you mapping twice first, in side the constructor and then again when it returns? - Anders
How you calling the addEmployer method of your model? With data coming from the server? Or directly within the page (e.g. from a binding, either directly or not)? - Grim
@Grim calling it from a binding. i added the code. - Sonic Soul

2 Answers

0
votes

You problem is that you do not add any data when mapping in the add function

Either: give it a dummy data object http://jsfiddle.net/mfauL/1/

this.Employers.push(new EmployerViewModel({ Name: "" }));

Or explicit declare the Name observable (Preffered way) http://jsfiddle.net/mfauL/2/

EmployerViewModel = function (data) { 
    this.Foo = ko.observable("bar"); 
    this.Name = ko.observable(); 

    ko.mapping.fromJS(data,{}, this); 
}; 
0
votes

Figured out a solution.

  1. expose the sub-class (sub-model) in question as a property of the main Model

    public ResumeEmployer EmptyEmployer { get { return new ResumeEmployer(); } }

  2. create a JSON representation of it

    var newEmployerJson = @Html.Raw(Json.Encode(Model.EmptyEmployer));

  3. when creating new employer on the client, use the empty definition json for bindings

        var Employer = function (data) { 
            if (data)
                ko.mapping.fromJS(data,{}, this);   // existing data in serialized model
            else
                ko.mapping.fromJS(newEmployerJson, {}, this); // json of single empty Employer class 
            ... 
         }