kemakino
kemakino

Reputation: 1122

Binding the Result of a Function in Knockout.js

I ran into an issue with creating a view model with Knockout.js. The point what I would like to ask is the way to implement a binding of a function that uses an observable as an argument.

I have these classes of Entity Framework:

public class Actor
{
    public int Id { get; set; }
    public string ActorName { get; set; }
    public List<ActorCurrentStatus> ActorStatuses { get; set; }
}

public class ActorCurrentStatus
{
    public long Id { get; set; }
    public double Rating { get; set; }
    public MatchType MatchType { get; set; }
    public string CurrentStatusIndicator { get; set; }
    //Foreign Key Conditions
    public long Actor_Id { get; set; }
    public virtual Actor Actor{ get; set; }
}

public enum MatchType
{
    type_team,
    type_ffa
}

public class ActorsListViewModel //View Model (not in database)
{
    public int Id { get; set; }
    public List<Actor> Actors { get; set; }
}

Controller passes the list of Actor to the view:

public ActionResult ActorsList()
{
    ActorsListViewModel vm= new ActorsListViewModel();
    viewModel.vm= _db.Actors.ToList();
    return View(vm);
}

Then a js object is created in the view:

<script type="text/javascript">
    var model = @Html.Raw(JsonConvert.SerializeObject(Model, Formatting.Indented,
                    new JsonSerializerSettings()
                    {
                        ReferenceLoopHandling = ReferenceLoopHandling.Ignore
                    }));
</script>

And it gets to be a viewModel by ko.mapping.fromJS with the following mapping option:

var mapping = {
    create: function (raw) {
        var modelBase = ko.mapping.fromJS(raw.data);
        //using linq.js
        modelBase.getActorStatus = function (data, modeStr) {
            return Enumerable.From(ko.mapping.toJS(data)).Single(t => t.CurrentStatusIndicator == modeStr);
        }
        modelBase.mode = ko.observable('type_team');
        return modelBase;
    }
}

var viewModel = ko.mapping.fromJS(model, mapping);
ko.applyBindings(viewModel);

Here this works correctly:

<div data-bind="foreach: Actors()">
    <div data-bind="text: $parent.getActorStatus(ActorStatuses ,'type_team').Rating"></div>
</div>

But I have a problem when I try to use the observable of modelBase.mode to set a condition for the binding, so I have inserted these contents to the view:

<button data-bind="click: ChangeMode('type_team')">TYPE_TEAM</button>
<button data-bind="click: ChangeMode('type_ffa')">TYPE_FFA</button>

and change the binding to:

<div data-bind="text: $parent.getActorStatus(ActorStatuses ,$parent.mode).Rating"></div>

Where the function ChangeMode is like this:

function ChangeMode(str) {
    switch (str) {
        case 'type_team':
            viewModel.mode = 'type_team';
            break;
        case 'type_ffa':
            viewModel.mode = 'type_ffa';
            break;
        default:
            break;
    }
}

After changing the binding, the view starts to display actors' rating of type_ffa when it is loaded and won't to update the information when I click the buttons.

Could anyone suggests what faults are there in the code and the structure?

Upvotes: 0

Views: 1051

Answers (2)

muhihsan
muhihsan

Reputation: 2350

Observable object requires you to assign the value by passing it as an argument. So it needs you to do the following:

function ChangeMode(str) {
  switch (str) {
    case 'type_team':
        viewModel.mode('type_team');
        break;
    case 'type_ffa':
        viewModel.mode('type_ffa');
        break;
    default:
        break;
  }
}

Also from the way ChangeMode function is structured, I believe the function is not bind together when ko.applyBindings is called. Which means this is just a normal javascript function. Therefore you can't use data-bind: click to trigger this and instead use a normal onclick.

<button onClick="ChangeMode('type_team')">TYPE_TEAM</button>
<button onClick="ChangeMode('type_ffa')">TYPE_FFA</button>

Upvotes: 1

adarsh
adarsh

Reputation: 121

Check this link http://knockoutjs.com/documentation/click-binding.html

You need to bind the ChangeMode function in mapping.

Upvotes: 1

Related Questions