0

Here is a fiddle

I have this html:

<div class="margin:0px; padding:0px; outline:0; border:0;" data-bind="with: notesViewModel">
        <table class="table table-striped table-hover" data-bind="with: notes">
            <thead><tr><th>Date Logged</th><th>Content</th><th>Logged By</th><th></th></tr>
            </thead>
            <tbody data-bind="foreach: allNotes">
                <tr>
                    <td data-bind="text: date"></td>
                    <td data-bind="text: compressedContent"></td>
                    <td data-bind="text: logged"></td>
                    <td><img src="/images/detail.png" data-bind="click: $root.goToNote.bind($data, $index())" width="20" alt="Details"/></td>
                </tr>
            </tbody>
        </table>

        <div class="noteView" data-bind="with: chosenNote">
            <div class="info">
                <p><label>Date:</label><span data-bind="text: date"></span></p>
                <p><label>Logged:</label><span data-bind="text: logged"></span></p>
            </div>
            <p class="message" data-bind="html: content"></p>
            <button class="btn btn-default" data-bind="click: $root.toNotes">Back to Notes</button>
        </div>

        <div class="editor-label" style="margin-top:10px">
            Notes
        </div>
        <div class="editor-field">
            <textarea id="contact_note" rows="5" class="form-control" data-bind="value: $root.noteContent"></textarea>
            <p data-bind="text: $root.characterCounter"></p>
            <button class="btn btn-info" data-bind="click: $root.saveNotes">Save</button>
            <div data-bind="html: $root.status">

            </div>   
        </div>
    </div>

And this JavaScript using knockout:

var notesViewModel = function () { 
    var self = this;
    self.notes = ko.observable(null);
    self.chosenNote = ko.observable();
    self.allNotes = new Array();
    self.user = "user1";
    // behaviours
    self.goToNote = function (noteIndex) {
        self.notes(null);
        self.chosenNote(new note(self.allNotes[noteIndex]));
    };
    self.toNotes = function () {
        self.chosenNote(null);
        self.notes({ allNotes: $.map(self.allNotes, function (item) { return new note(item); }) });
        console.log(self.notes());
    }

    self.noteContent = ko.observable();
    self.saveNotes = function () {
        var request = $.ajax({
            url: "EnquiryManagement/Contact/SaveNotes",
            type: "GET",
            dataType: "json",
            data: { id: "1322dsa142d2131we2", content: self.noteContent() }
        });
        request.done(function (result, message) {
            var mess = "";
            var err = false;
            var imgSrc = "";
            if (message = "success") {
                if (result.success) {
                    mess = "Successfully Updated";
                    imgSrc = "/images/tick.png";
                    self.allNotes.push({ date: new Date().toUTCString(), content: self.noteContent(), logged: self.user });
                    self.toNotes();
                } else {
                    mess = "Server Error";
                    imgSrc = "/images/redcross.png";
                    err = true;
                }
            } else {
                mess = "Ajax Client Error";
                imgSrc = "/images/redcross.png";
                err = true;
            }

            self.status(CRTBL.CreateMessageOutput(err, mess, imgSrc));
            self.noteContent(null);
            setTimeout(function () {
                self.status(null);
            }, 4000);
        });
    };
    self.status = ko.observable();

    self.characterCounter = ko.computed(function () {
        return self.noteContent() == undefined ? 0 : self.noteContent().length;
    });
};

var note = function (data) {
    var self = this;
    console.log(data.date);
    self.date = CRTBL.FormatIsoDate(data.date);
    self.content = data.content;
    self.compressedContent = data.content == null ? "" : data.content.length < 25 ? data.content : data.content.substring(0, 25) + " ...";
    self.logged = data.logged;
    console.log(this);
};

ko.applyBindings(new notesViewModel());

When I first load the page it says:

Uncaught Error: Unable to parse bindings. Message: ReferenceError: notes is not defined; Bindings value: with: notes

However, I pass it null, so it shouldn't show anything, because when I do the function goToNote then do goToNotes it sets the notes observable to null

So why can't I start off with this null value?

3
  • Can you recreate this in a fiddle? Also if you are instantiating a view model have you tried making it an anonymous function instead of a function assigned to a variable? That may not sound right but imaging using function notesViewModel instead of var notesViewModel = function or not using new in the applyBindings. I threw your code into a fiddle and it looks to work as expected if you remove the with: notesViewModel binding... Commented Feb 10, 2014 at 18:10
  • Don't know if it's the reason for your error but if (message = "success") should be if (message === "success"). Also, you should use === to compare. Commented Feb 10, 2014 at 18:16
  • @PWKad added fiddle link to the OP Commented Feb 10, 2014 at 18:21

2 Answers 2

2

The problem is where you have:

<div data-bind="with: notesViewModel">

That makes it look for a property "notesViewModel" within your notesViewModel, which does not exist.

If you only have one view model you can just remove that data binding and it will work fine.

If, however, you wish to apply your view model to just that div specifically and not the entire page, give it an ID or some other form of accessor, and add it as the second parameter in applyBindings, as follows:

HTML:

<div id="myDiv">

JS:

ko.applyBindings(new notesViewModel(), document.getElementById('myDiv'));

This is generally only necessary where you have multiple view models in the same page.

Sign up to request clarification or add additional context in comments.

4 Comments

Yeah i already fixed that, So my assumption is that if you have multiple viewModels per page its best to do: ko.applyBindings({ mainViewModel: new mainViewModel(), notesViewModel: new notesViewModel}) Now I'm getting another error see fiddle
Your new problem is completely unrelated - it tells you exactly what is wrong in console...
$root.notesViewModel.goToNote.bind($data, $index())
it turns out it doesnt need to fixed, I cleared console, refreshed the page and it worked perfectly fine, however, I still like your comment because it shows how to access certain viewModels in a multi viewModel scenario
0

Like what bcmcfc has put, however, due to my scenario being a multi-viewModel scenario I don't think his solution is quite the right one.

In order to achieve the correct results, first of all I extrapolated out the self.notes = ko.observable(null); into a viewModel which makes doing the table binding far easier.

Then to fix the binding issues instead of setting an element for the bind to take place, I merely did this:

ko.applyBindings({
    mainViewModel: new mainViewModel(),
    notesViewModel: new notesViewModel()
});

In my original code I have two viewModels which is why I was getting this error. With this method the key is:

I don't create dependancies!

Instead of tieing the viewModel to a certain dom element which can change quite easily and cause having to go and changes things with ko, plus if I add more viewModels then it can get more complicated. I simply do:

data-bind="with: viewModel"

That way I can bind to any DOM object and I can have has many as I like.

This is the solution that solved my post.

Here is the jsfiddle

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.