简体   繁体   中英

Insert a new inner object into array of objects observable array and update the DOM

HTML with bindings:

<div class="container" data-bind="foreach: { data: Conferences, as: 'conf' }">
    <div class="conf" data-bind="attr: { id : conf.Id }">
        <div class="conf-month" data-bind="text: conf.StartTime"></div>
        <div class="conf-day" data-bind="text: conf.EndTime"></div>
        <div class="add-user">
            <input type="tel" data-bind="value: $root.PhoneNumber />
            <input type="email" data-bind="value: $root.Email" />
            <a id="add-user" title="Add new user" data-bind="attr: { value: conf.Id }, click: $root.addUserToConference">Add</a>
        </div>
        <div class="conf-users" data-bind="foreach: { data: conf.ConferenceUsers, as: 'user' }">
            <div class="conf-user" data-bind="attr: { id: 'confuser-' + user.Id}">
                <span data-bind="text: user.Name"></span>
                <span data-bind="text: user.PhoneNumber"></span>
                <span data-bind="text: user.Email"></span>
            </div>
        </div>
    </div>
</div>

KnockoutJs ViewModel:

function ConferenceViewModel() {
    var self = this;

    self.Conferences = ko.observableArray([]);
    self.PhoneNumber = ko.observable("");
    self.Email = ko.observable("");


self.getAllConfs = function () {
        $.ajax({
            type: 'GET',
            url: '/confs/getconfs',
        }).done(function (confs) {
            $.each(confs, function (index, conf) {
                    //populate the list on document ready
                    confVm.Conferences.push(conf);
            };
        }).fail(showError);
}

self.addUserToConference  = function (viewModel, event) {
    var user = {
        "Id": 0,
        "ConferenceId": viewModel.Id(),
        "Email": "self.Email()",
        "PhoneNumber": self.PhoneNumber(),
    };  

    // here we should insert a new ConferenceUser into the Conferences observable array
    // and also update the DOM 

    // ajax to insert user to db
}

After I populate the above Conferences observableArray via ajax, the output of console.log(ko.toJSON(confVm.Conferences())) is as follows:

[  
   {  
      "ConferenceUsers":[  
         {  
            "Id":3006,
            "ConferenceId":8,
            "Name":null,
            "Email":"mail@lala.com",
            "UserName":null,
            "PhoneNumber":"234234234234",
            "ChannelId":null,
            "State":null,
            "Type":null,
            "RecordingId":null
         }
      ],
      "Id":8,
      "Subject":"YYYhaaaaa",
      "StartTime":"2016-05-29T18:30:00",
      "EndTime":"2016-05-29T19:30:00",
      "OrganizerEmail":"elpas@live.com",
      "OrganizerName":"dasdasd",
      "Pin":"6402",
      "BridgeId":null,
      "State":null
   },
   {  
      "ConferenceUsers":[  
         {  
            "Id":3013,
            "ConferenceId":12,
            "Name":null,
            "Email":"dsfdfsdfdsf@dfdfdf.com",
            "UserName":null,
            "PhoneNumber":null,
            "ChannelId":null,
            "State":null,
            "Type":null,
            "RecordingId":null
         }
      ],
      "Id":12,
      "Subject":"dsfsdfdsfsdf",
      "StartTime":"2016-05-31T22:00:00",
      "EndTime":"2016-05-31T23:00:00",
      "OrganizerEmail":"d@adssad.com",
      "OrganizerName":"dsfdsfsdf",
      "Pin":"3402",
      "BridgeId":null,
      "State":null
   }
]

Q: How can I insert a new ConferenceUser by ConferenceId and update the DOM accordingly?

Try this:

var obj = [  
   {  
      "ConferenceUsers":[  
         {  
            "Id":3006,
            "ConferenceId":8,
            "Name":null,
            "Email":"mail@lala.com",
            "UserName":null,
            "PhoneNumber":"234234234234",
            "ChannelId":null,
            "State":null,
            "Type":null,
            "RecordingId":null
         }
      ],
      "Id":8,
      "Subject":"YYYhaaaaa",
      "StartTime":"2016-05-29T18:30:00",
      "EndTime":"2016-05-29T19:30:00",
      "OrganizerEmail":"elpas@live.com",
      "OrganizerName":"dasdasd",
      "Pin":"6402",
      "BridgeId":null,
      "State":null
   },
   {  
      "ConferenceUsers":[  
         {  
            "Id":3013,
            "ConferenceId":12,
            "Name":null,
            "Email":"dsfdfsdfdsf@dfdfdf.com",
            "UserName":null,
            "PhoneNumber":null,
            "ChannelId":null,
            "State":null,
            "Type":null,
            "RecordingId":null
         }
      ],
      "Id":12,
      "Subject":"dsfsdfdsfsdf",
      "StartTime":"2016-05-31T22:00:00",
      "EndTime":"2016-05-31T23:00:00",
      "OrganizerEmail":"d@adssad.com",
      "OrganizerName":"dsfdsfsdf",
      "Pin":"3402",
      "BridgeId":null,
      "State":null
   }
];


/* Iterate all conferences */
for (var i in obj) {

  /* Find conference with ID = 8 */
  if (obj[i].Id === 8) {

    /* Add a new user to the conference */
    obj[i].ConferenceUsers.push({

      "Id":1111,
      "ConferenceId":1,
      "Name":null,
      "Email":"test@example.com",
      "UserName":null,
      "PhoneNumber":null,
      "ChannelId":null,
      "State":null,
      "Type":null,
      "RecordingId":null

    });

    break;
  }
}

console.log(obj); // output result

You'll need to execute four steps:

  1. Get the current list of conferences from the observable array Conferences
  2. Find the conference with the right id
  3. Push a new user to this conference's ConferenceUsers
  4. Make sure Conferences is set with the new data

While all steps are pretty straight forward to execute, there'll be some drawbacks to how they'd work:

The Conference objects and the ConferenceUsers arrays aren't observable. Knockout isn't automatically aware of any changes inside the Conference objects. So, after step 3 and 4 , to knockout, it won't appear as if anything's changed: the Conferences array still has the same objects in it.

My advice:

If adding new users to conferences is something that will happen regularly, I'd suggest creating a Conference viewmodel that has a ko.observableArray of users. Alternatively, you could create new Conference objects for every minor change, which will trigger knockout to re-render the entire UI instead of just the relevant part (assuming you've used a foreach data-bind somewhere).

A quick example of how you could map your regular Conference objects to viewmodels:

 // Your JSON data from the ajax request (an array of objects) var conferencesData = []; var Conference = function(conferenceJSON) { // It's better to map all properties you're using individually, // but this at least exposes the original JSON object this.props = conferenceJSON; this.users = ko.observableArray(conferenceJSON.conferenceUsers); }; var createConference = function(conferenceJSON) { return new Conference(conferenceJSON); }; var ConferenceList = function(conferencesJSON) { var self = this; this.conferences = ko.observableArray(conferencesJSON.map(createConference)); this.addConference = function(conferenceJSON) { self.conferences.push(createConference(conferenceJSON)); }; this.addUserToConference = function(userJSON) { var conferences = self.conferences(); for (var c = 0; c < conferences.length; c += 1) { // Step 2: Find the conference with the required id if (conferences[c].props.id === userJSON.ConferenceId) { // Step 3: We're pushing to an observableArray, so no need // to worry about Step 4. conferences[c].users.push(userJSON); return true; } } return false; }; }; ko.applyBindings(new ConferenceList(conferencesData)); 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM