<repo_name>t3patterson/explorations-knockoutjs<file_sep>/02-observable-arrays.md
##Obserbale Arrays
###Knockout in JS - Observable Arrays (@ source)
1. Put `ko.observable` on the data-type
2. Append observables to an array and pass array as argument to `ko.observable`
3. Establish bindings by passing the array as the vale of a name-spaced property to `ko.applyBindings`

```js
  var Person = function(name){
    //(1)
    this.name = ko.observable(name)
  }

  var p1 = new Person('Travo'),
      p2 = new Person('Roberto')
    
  //(2)
  var viewModel = {people: ko.observableArray([p1,p2])};

  //(3)
  ko.applyBindings(viewModel)

```

In HTML data can be accessed under `people()` namespace:
``` 
    <h3>Records</h3> 
    <p data-bind="text: people().length"></p>

    <ul data-bind="foreach: people">
        <li data-bind="text: name"></li>
    </ul>
```

Observables will you allow to change the value from the input:
```
  <ul data-bind="foreach: people">
    <li>
        <span data-bind="text: name"></span>
        <input type="text" data-bind="value: name"/>
    </li>
  </ul>
```

When you change the `input` with a `data-bind="value: «»"` , the `<span>` tag will change to match. This is because we passed the original value that generated the name to a *ko.observable*

Note: observables are *functions* that require `()` 
```html
 <p> Records <span data-bind="text: people().length"></span></p>
 <p>First Person: <span data-bind="text: people()[0].name"></span>
```
**EXCEPT** for the 'right-most' property which is automatically 'unwrapped' 
```html
<ul data-bind="foreach: people">
  <li>
      <p data-bind="text: name"></p>
      <p data-bind="text: age"></p>
  </li>
<ul>
```
(however you can use the `()`)

####Sometimes you might not need observables:
- Read Only
- One Time Binding
- Loading a list of objects
...
- Example of mix & match:  
  ```js
  var Person = function (_name,_age,_id){
    this.id = _id;
    this.name = ko.observable(_name);
    this.age = ko.observable(_age);
  }
  ```


##Debugging

####In the console

- **breakpoints** in `Sources`  for determining the code's
  + call stack
  + scope variables
  + 

- **conditional breakpoints**
  - a breakpoint to run if a function/event evaluates to t/f

- **Evaluate in Console**
  - right click under `Sources` tab in chrome
  - Use *Add to Watch* to watch certain variables

- **Workspaces**
  - Setup workspaces in Settins

- **XHR Breakpoints**

##Inspecting Bindings
####In `.js`
```
 viewModel = {
    ...
    bindingInfo: ko.computed(function(){
      return ko.toJSON(«ko-observable item/array»,null,2);
    })
 };
  
 ko.applyBindings(viewModel);
```

####In `.html`
```

```

###Create DOM-node with bindings using custom `ko.addBindingHandlers` method
**The HTML**
```html
<div data-bind="dump: people"></div>
```

**The JS**
Note: 
`domElement` --> DOM element
`valueAccessor()` *i.e. the context* --> people
`dump` --> the name of the bindingHandler

```js
ko.bindingHandlers.dump = {
  init: function(domElement, valueAccessor, allBindingsAccessor,viewModel,bindingContext){
    
    var context = valueAccessor();
    var allBindings = allBindingsAccessor();
    var pre = document.createElement('pre');
    
    domElement.appendChild();
    
    var dumpJSON = ko.computed({
      
      read: function(){
        ko.toJSON(context,null,2)
      },

      disposeWhenNodeIsRemoved: domElement

    });

    ko.applyBindingsToNode(
      pre, 
      {text: dumpJSON} 
    )

  }
}
```

##Misc-DEV Tips
####Iterate clean over an object
`for-in` loops also iterate over the prototype. to avoid this:

```
 for (var prop in this){
    if (this.hasOwnProperty(prop)){
      //do x
    }
 }
```<file_sep>/app-sessions.js
window.onload = (function(){
    //observables
    // sessions() - observable-array
    //
    // sessions
    // speaker
    //   imageName
    //   fullName
    // timeSlot
    //   name
    // room
    //   name
    // level
    // track
    //  trackname
    // code
    // title
    // tagsFormatted

    function Session(ops){
      if ( ops.speaker ){
          this.speaker = {
              fullName : ops.speaker.fullName || "",
              imageName : ops.speaker.imageName ||""
          }
      } else {
          this.speaker = {
              fullName:"",
              imageName: ""
          }
      }

      this.room = ops.room || ""
      this.code = ops.code || ""
      this.title = ops.title ||""
      this.tagsFormatted = ops.tagsFormatted  || "no tages"

      this.level = ops.level || ""

      if ( ops.track ){

          this.track = {
              name: ops.track.name || ""
          }

      } else {
          ops.track = {
              name: ""
          }
      }

      if ( ops.timeSlot ){

          this.timeSlot = {
              name: ops.timeSlot.name || ""
          }

      } else {

          ops.timeSlot = {
              name: ""
          }
      }

      this.createObservables()
    }

    Session.prototype.createObservables = function(){
        for (var prop in this){
            ko.observable(this[prop])
        }
    }

    var user1 = {
        speaker: {
            fullName: "<NAME>",
            imageName: "https://randomuser.me/api/portraits/men/0.jpg"
        },
        timeSlot: { name: "Saturday 10pm"},
        room: {name: "Moon Room"},
        level: "4",
        track: {name: "Programming"},
        code: "#9f8f9-e0a",
        title: "How to be the man",        
        tagsFormatted: "Study, Work, Play"
     }

    var user2 = {
        speaker: {
            fullName: "<NAME>",
            imageName: "https://randomuser.me/api/portraits/men/3.jpg"
        },
        timeSlot: { name: "Wednesday 4pm"},
        room: {name: "Cloud Room"},
        level: "2",
        track: {name: "Intro to Everythgin"},
        code: "#37829-e0a",
        title: "Crawl before you walk",        
        tagsFormatted: "Intro, Start, Learn"
     }

    var evt = new Session(user1);
    var evt = new Session(user2);

    
    var viewModel = {
        sessions: ko.observableArray([user1,user2])
    }
    
    ko.applyBindings(viewModel)
})();<file_sep>/01-simple-binding.md
##Simple Binding Example
####The HTML
```html
<input type="text" data-bind="value: person().name">
...
<tr>
  <td data-bind="text: person().name"></td>
  <td data-bind="text: person().age"></td>
</tr>
```


####The JS
```js
function Person(name, age){
  this.name = ko.observable(name)
  this.age = ko.observable(age)
}

var p1 = new Person("Travoo", 29);

var viewModel = {
  person: ko.addObservable(p1)
}

viewModel
```

var p1 = {
  name: "Travo",
  age: 33
}

var viewModel = {
  person: ko.observable(p1)
}

ko.applyBindings(viewModel);


###Knockout in HTML/View (Read Only Target)
uses `data-bind` attribute

```
<section data-bind="foreach: speakers">
  <article>
    <img data-bind="attr: {src: imageName}"/>
    <p>
        <span data-bind="text: firstName"></span>
        <span data-bind="text: lastName"></span>
    </p>
  </article>
</section>
```
<file_sep>/README.md
#Knockout Notes
1. [The Basics](./00-the-basics.md)
2. [Simple Binding](./01-simple-binding.md)
3. [Observable Array](./02-observable-arrays.md)
4. [Inspecting Bindings](./03-inspect-bindings.md)


##Misc-DEV Tips / Things Learned
####Iterate clean over an object
`for-in` loops also iterate over the prototype. to avoid this:

```
 for (var prop in this){
    if (this.hasOwnProperty(prop)){
      //do x
    }
 }
```<file_sep>/dump.js
//ko.bindingHandler.dump
ko.bindingHandlers.dump = {
  init: function(ko_element, valueAccessor, allBindingsAccessor, viewModel, bindingContext  ){
    // ko_element - is the DOMelement that you're bound to
    // valueAccessor - value your bound to 
    // allBindingsAccessor - other bindings on that particular element
    // viewModel - whatever the page is bound to
    // bindingContext - ???

    var context = valueAccessor(); // the ko-observable we're referencing/bound to 
    var allBindings = allBindingsAccessor(); //ko-observable
    var pre = document.createElement('pre');

    ko_element.appendChild(pre); //appends to KO element 

    var dumpJSON = ko.computed({
      read: function(){
        return ko.toJSON(context,null,2);
      },
      disposeWhenNodeIsRemoved: ko_element
    });

    ko.applyBindingsToNode(
      pre, {text: dumpJSON}
    );
  }
} 
<file_sep>/03-inspect-bindings.md
##Inspect Bindings

###Debugging in the console

- **breakpoints** in `Sources`  for determining the code's
  + call stack
  + scope variables
  + 

- **conditional breakpoints**
  - a breakpoint to run if a function/event evaluates to t/f

- **Evaluate in Console**
  - right click under `Sources` tab in chrome
  - Use *Add to Watch* to watch certain variables

- **Workspaces**
  - Setup workspaces in Settins

- **XHR Breakpoints**

### Using `ko.computed` in `.js` as a k
```
 viewModel = {
    ...
    bindingInfo: ko.computed(function(){
      return ko.toJSON(«ko-observable item/array»,null,2);
    })
 };
  
 ko.applyBindings(viewModel);
```

####In `.html`
```
 <pre data-bind="text: bindingInfo">
```

###Create DOM-node with custom bindings using  `ko.addBindingHandlers` method
**The HTML**
```html
<div data-bind="dump: people"></div>
```

**The JS**
Note: 
`domElement` --> DOM element
`valueAccessor()` *i.e. the context* --> people
`dump` --> the name of the bindingHandler

```js
ko.bindingHandlers.dump = {
  init: function(domElement, valueAccessor, allBindingsAccessor,viewModel,bindingContext){
    
    var context = valueAccessor();
    var allBindings = allBindingsAccessor();
    var pre = document.createElement('pre');
    
    domElement.appendChild();
    
    var dumpJSON = ko.computed({
      
      read: function(){
        ko.toJSON(context,null,2)
      },

      disposeWhenNodeIsRemoved: domElement

    });

    ko.applyBindingsToNode(
      pre, 
      {text: dumpJSON} 
    )

  }
}
```

<file_sep>/00-the-basics.md
## The Basics
##Based on Observables
Observables are *critical* to knockout. 

**3-Types**
1. Observable
2. Observable-Array
3. Computed

How it looks:
```
var name = ko.observable('Travis')
var age = ko.observable(32)
```

### 2Way Data Binding
```
*Event Happens* @ source ---> Target is notified
Source is notified       <--- *Event Happens:* @ target
```

Notes
- [Simple Binding Example](./index0.html)
- []

###Knockout in JS - Observable Arrays (@ source)
1. Put `ko.observable` on the data-type
2. Append observables to an array and pass array as argument to `ko.observable`
3. Establish bindings by passing the array as the vale of a name-spaced property to `ko.applyBindings`

```js
  var Person = function(name){
    //(1)
    this.name = ko.observable(name)
  }

  var p1 = new Person('Travo'),
      p2 = new Person('Roberto')
    
  //(2)
  var viewModel = {people: ko.observableArray([p1,p2])};

  //(3)
  ko.applyBindings(viewModel)

```

In HTML data can be accessed under `people()` namespace:
``` 
    <h3>Records</h3> 
    <p data-bind="text: people().length"></p>

    <ul data-bind="foreach: people">
        <li data-bind="text: name"></li>
    </ul>
```

Observables will you allow to change the value from the input:
```
  <ul data-bind="foreach: people">
    <li>
        <span data-bind="text: name"></span>
        <input type="text" data-bind="value: name"/>
    </li>
  </ul>
```

When you change the `input` with a `data-bind="value: «»"` , the `<span>` tag will change to match. This is because we passed the original value that generated the name to a *ko.observable*

Note: observables are *functions* that require `()` 
```html
 <p> Records <span data-bind="text: people().length"></span></p>
 <p>First Person: <span data-bind="text: people()[0].name"></span>
```
**EXCEPT** for the 'right-most' property which is automatically 'unwrapped' 
```html
<ul data-bind="foreach: people">
  <li>
      <p data-bind="text: name"></p>
      <p data-bind="text: age"></p>
  </li>
<ul>
```
(however you can use the `()`)

####Sometimes you might not need observables:
- Read Only
- One Time Binding
- Loading a list of objects
...
- Example of mix & match:  
  ```js
  var Person = function (_name,_age,_id){
    this.id = _id;
    this.name = ko.observable(_name);
    this.age = ko.observable(_age);
  }
  ```
