knockout show editable table - javascript

In knockout i have a foreach data-binding to populate a table:
...
<tbody data-bind="foreach: people">
<tr>
<td>
<span data-bind="text: $data.Name"></span>
</td>
<td>
<span data-bind="text: $data.Description"></span>
</td>
</tr>
</tbody>
...
In the script section:
self.people= ko.observableArray();
$.getJSON('/api/apipeople', self.people);
With this code i'm able to see a table with the people name and description.
Now i want make the table fields editable so i've changed the
<span data-bind="text: $data.Name">
to
<span data-bind="value: $data.Name">
Why i don't see anything with data-bind = value? The object self.people contains all the data so why with 'text' binding i'm able to see the values and with 'value' binding i don't see anything?

The "value" attribute is not defined for "span" elements.
It is defined for elements such as "input" or "textarea".
For editable table you can follow this example - link

Related

How to conditionally change column to textbox in AngularJS grid?

I want to know how to add one particular column value as textbox in an AngularJS grid.
So, I am implementing an AngularJS grid as below:
<div>
<table>
<tr>
<th>
<td>Customer Account Number</td>
<td>Customer Name</td>
</th>
</tr>
<tbody>
<tr ng-repeat="item in data">
<td>{{item.CustomerAccNumber}}</td>
<td>{{item.CustomerName}}</td>
</tr>
</tbody>
</table>
<input type=button value="Add Row" ng-click="Add()"/>
So, in scenario 2 things happen:
By default I am getting few records as "Customer Account Number" and "Customer Name".
But there is an "Add Row" button on the same page I need to implement which adds a new row to the grid.
The first column "Customer Account Number" is a text box and second row is noneditable.
So, how to place textbox as a column only when adding a new row from button?
Let's say after adding add row my first column is coming as text box, so after entering the account number in the textbox on textchange it should fetch the customer account number and display it in the same row.
Can someone help me figure out how to put the textbox into one particular column in grid?
Can it be done the way I have implemented the grid?
I don't want to use nggrid.
I would do something like this:
First, in your Controller, in your Add() function, when you push a new row, add a field such as isEditable to allow you to differentiate between a newly added row in the UI.
$scope.Add = function() {
$scope.data.push({
'CustomerAccNumber': 1,
'CustomerName': '',
'isEditable': true // field to identify new row
})
}
Then in your markup, having that flg available, you can leverage ngIf, like so:
<tr ng-repeat="item in data">
<td ng-if="!item.isEditable">{{item.CustomerAccNumber}}</td>
<td ng-if="item.isEditable">
<input type="text" ng-model="item.CustomerAccNumber">
</td>
<td>{{item.CustomerName}}</td>
</tr>
it should fetch CustomerAccount number
As far as your third item, you can use ngBlur to make a call when the user clicks out of the box:
1) Define a function in your controller to call when the user leaves the box.
$scope.doSomethingWithAccNumber() {
// $http call, etc
}
2) Update your textbox to use the ngBlur directive that will trigger when the user clicks out.
<td ng-if="item.isEditable">
<input type="text"
ng-model="item.CustomerAccNumber"
ng-blur="doSomethingWithAccNumber()">
</td>
If you want other keys to trigger this, you can use ngKeydown as well. Use of this is outlined well here. For example, you would want to add ng-keydown="$event.keyCode === 13 && doSomethingWithAccNumber()" to your input to trigger on Enter.

Angular.js ngTable select input as a column not showing the existing value

I'm using Angular.js 1.2 and I'm trying to use a Select input in the cell of an ngTable. The Option list populates but the ngModel directive doesn't seem to select the item for display.
This is what my table looks like at the moment:
<table class="col-xs-12 table" data-ng-table>
<tr data-ng-repeat="task in template.tasks">
<td data-title="'Category'">
<select class="form-control template-task-category" data-ng-model="task.categoryId" data-ng-options="category.description for category in taskCategories track by category.id"></select>
</td>
<td data-title="'Description'">
<input class="form-control template-task-description center-block" data-ng-model="task.description"/>
</td>
<td data-title="'Default Role'">
<select class="form-control" data-ng-model="task.defaultRoleId" data-ng-options="role.Name for role in roles track by role.id"></select>
</td>
<td data-title="'Est. Hours'">
<input class="form-control template-task-hours center-block" data-ng-model="task.estimatedHours"/></td>
<td data-title="'Order'"><input class="form-control template-task-sort center-block" data-ng-model="task.sortOrder"/>
</td>
<td data-title="'Remove'">
</td>
</tr>
</table>
The Category and Default Role columns always show as un-selected dropdowns, and when I display the task.categoryId and task.defaultRoleId directly they do have values that are part of the Options list. Is there something more I need to do here?
Edit
Here's an example. What I was expecting was for the dropdowns to have the associated value selected. http://plnkr.co/edit/9DkSQT?p=preview
I figured it out. The ng-model needed to point at a full instance of the associated object and not just the property that held the id. In my class I had both an Id field (that mimicked the database table) and the associated instance. Binding to the instance (task.taskCategory instead of task.categoryId) fixed it.

Where do you put the form element if you have editable rows of a table in AngularJS?

We have a table(A) and we want a specific row to become editable on click. Currently we have a directive that inserts a new table into the td of table(A) where it is called. We do this so we can use the <form> element around the table.
uneditable-table.html
<table>
<tbody>
<tr>
<td ng-show="editing" class="editing" colspan="2">
<div edit-form-directive
model="thing"
on-success="thingUpdated(thing); editing=false;"
on-cancel="editing=false; setUpdating(false);"
enabled="editing" />
</td>
</tr>
</tbody>
</table>
edit-template.html inserted via the editFormDirective
<form ng-submit="save(thingCopy)" name="EditForm">
<table>
<tbody>
<tr>
<td>
<input ng-model="thing.field1"/>
</td>
<td>
<input ng-model="thing.field2"/>
</td>
</tr>
</tbody>
<table>
</form>
Question:
We have tried putting the <form> element around each row to be editable, and this works, however, this is not semantically correct with the <form> around a <tr> within a table.
We also considered putting the <form> around the entire table in uneditable-table.html. This causes a form validation issue, where we may have many errors per non-unique form node, so we would have to index the nodes to get specific errors.
We settled on the code as it is here, with having the <form> element around a whole new table (in edit-template.html) and inserting that into a <td>, as this seemed the least harmful.
We do have to have the form tag so we can access validation based on the form name and nodes.
Is there a more Angular (or elegant) way to do this?
Thank you!
Angular way. Form tag isn't needed:
<table ng-form="EditForm">
...
</table>
http://docs.angularjs.org/api/ng.directive:ngForm

Knockout table row access

First off, forgive the hard coded table data. I am doing a simple add row type of thing. I'm wondering how to get at the data in the sibling TDs. Should I be using a form? Or something else? basically I just need access to the data that is already in there and move it to another table.
<tbody data-bind="foreach: Resources">
<tr>
<td data-bind="text: name">
</td>
<td data-bind="text: type">
</td>
<td data-bind="text: contact">
</td>
<td data-bind="text: status">
</td>
<td>
<input type="button" data-bind="click: addResourceToList" value="Add Resource" />
</td>
</tr>
</tbody>
Here is the start of the code in the model.
addResourceToList = function () {
self.ResourcesInPlan.push(new ResourceListModel({ name: this.title }));
};
Thanks for any advice.
Update: The data was there, but I missed it. I changed to this line.
self.ResourcesInPlan.push(new ResourceListModel(this.name));
Because I was referencing the model wrong as you can see.
See this example:
http://knockoutjs.com/documentation/click-binding.html#note_1_passing_a_current_item_as_a_parameter_to_your_handler_function
KO will send the item as the first parameter to the function too.

How to create unique ng-form tags on a form with ng-repeat in angular

I am trying to create a form part of which is a table that loops over a list of objects and for each object allows the user to check/uncheck attributes. The rest of the form works fine but I am having trouble setting the ng-model attribute on the checkboxes.
Here's what I have:
<table>
<thead>
<tr>
<td>Objects and Fields</td>
<td>Createable</td>
<td>Deleteable</td>
<td>Readable</td>
<td>Updateable</td>
</tr>
</thead>
<tbody>
<tr ng-repeat="object in myAppObjects">
<td>
{{object.name}} {{object.id}}
<input type="checkbox" name="app_access_{{object.id}}" ng-model="app_access" value="false">
</td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
At first I tried setting the ng-model="app_access_{{object.id}}" so that I would have a unique ng-model for each cell. This caused the table row to be repeated several dozen times. Each of those empty cells will also have a check box. There will be five check boxes for each object and several objects in the form at a given time. I'll need to be able to access each check box (or better yet a list of the checked ones) in the controller.
Since ngRepeat creates a new (child) scope for each item, creating new ng-models (that are tied to those new scopes) for the items will not work because those models/data will only be accessible inside those inner scopes. We can't write a controller function to access those inner/child scopes. It is better to reference something in myAppObjects for the models (like #Max suggests in his second example).
If myAppObjects looks something like this:
$scope.myAppObjects = [
{id: 1, cb1: true, cb2: false, cb3: true, cb4: true, cb5: false },
{id: 2, cb1: false, cb2: false, cb3: true, cb4: false, cb5: true },
You could write your ng-repeat like this:
<tr ng-repeat="appObj in myAppObjects">
<td>{{appObj.id}}
<input type="checkbox" ng-model="appObj.cb1"></td>
<td><input type="checkbox" ng-model="appObj.cb2"></td>
<td><input type="checkbox" ng-model="appObj.cb3"></td>
<td><input type="checkbox" ng-model="appObj.cb4"></td>
<td><input type="checkbox" ng-model="appObj.cb5"></td>
</tr>
Working fiddle: http://jsfiddle.net/mrajcok/AvGKj/
Bottom line: we need to have the checkbox models defined in/on the parent scope (in my fiddle, MyCtrl's $scope), and not in/on the ngRepeat inner/child scopes.
Generally, if you are iterating over a collection using ng-repeat then the the items that you display and edit are the individual members of the collection. So if you have an array of strings that are being edited by the ng-repeat you would do
<div ng-repeat="item in list">
<input ng-model="item" />
</div>
Or if is a list of objects you are iterating over you would do
<div ng-repeat="obj in list">
<input ng-model="obj.item" />
</div>

Categories