Skip to content Skip to sidebar Skip to footer

Get Object Out Of Observable Array

Why is m 'undefined' in this code: currentViewModel = ko.mapping.fromJS(viewModel); currentViewModel.getReport = function(reportId) { for(var i=0;i

Solution 1:

You just need to change if(currentViewModel.availableReports()[i].id ... to if(currentViewModel.availableReports()[i].id() ... because after mapping id will become an observable, i.e. function.

Updated code:

currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
    for (var i = 0; i < currentViewModel.availableReports().length; i++) {
        if (currentViewModel.availableReports()[i].id() == reportId) {
            var m = currentViewModel.availableReports()[i];
            return currentViewModel.availableReports()[i];
        }
    }
}

Demo - Fiddle.


Solution 2:

I'll repeat the solution from @NikolayErmakov's answer here, but want to add two things to get a more complete answer. You end with:

...m remains undefined and the function returns undefined.

What am I missing here?

You're missing two things:

  1. The var m bit of the first statement inside the if is hoisted to the top of the current scope (the top of the function). This is why the debugger can tell you what m is, even if you never reach the line of code it's on.
  2. If a function invocation reaches the end of a function (as is the case for you, since you never go inside the if) without seeing an explicit return statement, it will return undefined.

To better understand this, you should interpret your function like this:

currentViewModel.getReport = function(reportId) {
  var m;

  for (var i = 0; i < currentViewModel.availableReports().length; i++) {
    if (currentViewModel.availableReports()[i].id == reportId) {
      m = currentViewModel.availableReports()[i];
      return currentViewModel.availableReports()[i];
    }
  }

  return undefined;
}

Some people (e.g. Douglas Crockford) do recommend placing var statements at the top of a function, though it's a matter of style to some degree. I don't think many people explicitly return undefined at the end of a function, though in your case I might be explicit about that scenario and return null (or throw an Error even).

As promised, I'll repeat the actual solution, as I concur with the other answer:

  • you need to invoke id as a function to get its value (because the mapping plugin will map to observable()s.

In addition:

  • I'd retrieve the array only once
  • I'd suggest using === instead of ==

Here's my v0.5 version:

currentViewModel.getReport = function(reportId) {
    var m = null, reports = currentViewModel.availableReports();

    for (var i = 0; i < reports.length; i++) {
        if (reports[i].id() === reportId) {
            m = reports[i];
            return m;
        }
    }

    return m;
}

But I'd optimize it to this v1.0:

currentViewModel.getReport = function(reportId) {
    var reports = currentViewModel.availableReports();

    for (var i = 0; i < reports.length; i++) {
        if (reports[i].id() === reportId) {
            return reports[i];
        }
    }

    return null;
}

For completeness, here's another version that utilizes filter on arrays:

currentViewModel.getReport = function(reportId) {
  var reports = currentViewModel.availableReports().filter(function(r) { return r.id() === reportId; });
  return reports.length >= 1 ? reports[0] : null;
}

Post a Comment for "Get Object Out Of Observable Array"