Duplicated form after click button add - javascript

Anybody help me, I have these working code currently:
HTML:
<body ng-controller="ExampleCtrl">
<label>Category:</label>
<select ng-model="product.category" ng-options="category as category.name for category in categories"></select>
</label><br/><br />
<table class="table" ng-repeat="attr in product.category.templateAttribute">
<thead>
<tr>
<th colspan="4">{{attr.attribute}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input value="{{attr.attribute}}" />
</td>
<td>
<input placeholder="name" ng-model="product.attributes[attr.attribute].name" />
</td>
<td>
<input placeholder="additional price" ng-model="product.attributes[attr.attribute].additionalPrice" />
</td>
<td rowspan="2">
<button type="button" ng-click="addItem(product.category.templateAttribute, attr)">
add
</button>
</td>
</tr>
<tr>
<td colspan="3">
<input type="file" class="form-control" ng-model="product.attributes[attr.attribute].file"/>
</td>
</tr>
</tbody>
</table>
JS
function ExampleCtrl($scope){
$scope.categories = [
{
name:'custom',
templateAttribute: [
{attribute: 'material'},
{attribute: 'soles'},
{attribute: 'size'}
]
}
];
$scope.products = [
{
name: 'custom',
category: {
name:'custom',
templateAttribute: [
{
type: "string",
attribute: "material"
},
{
type: "string",
attribute: "soles"
},
{
type: "string",
attribute: "size"
}
]
}
}
];
// add menu item
$scope.addItem = function(list, item){
list.push(angular.copy(item));
item = {};
};
// remove menu item
$scope.removeItem = function(list, index){
list.splice(index ,1);
};
}
angular
.module('app', [])
.controller("ExampleCtrl", ExampleCtrl)
For a demo :
Seet Demo
My problem is when I fill out one form above and click on the add button, it will display a new form, but that form always has the same value. How to fix my problem?

item should be defined as {} before pushing in list array.
If you do not want to send any model data through view then there is no point of sending attr argument to controller
Try this:
// Code goes here
function ExampleCtrl($scope) {
$scope.categories = [{
name: 'custom',
templateAttribute: [{
attribute: 'material'
}, {
attribute: 'soles'
}, {
attribute: 'size'
}]
}];
$scope.products = [{
name: 'custom',
category: {
name: 'custom',
templateAttribute: [{
type: "string",
attribute: "material"
}, {
type: "string",
attribute: "soles"
}, {
type: "string",
attribute: "size"
}]
}
}];
// add menu item
$scope.addItem = function(list, item) {
item = {};
list.push(angular.copy(item));
};
// remove menu item
$scope.removeItem = function(list, index) {
list.splice(index, 1);
};
}
angular
.module('app', [])
.controller("ExampleCtrl", ExampleCtrl)
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js"></script>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.5/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="ExampleCtrl">
<h3>How to fix this</h3>
<p>My problem is when I fill out one form above and click on the add button, it will display a new form, but that form always has the same value. Demo:</p>
<label>Category:
<select ng-model="product.category" ng-options="category as category.name for category in categories"></select>
</label>
<br/>
<br />
<table class="table" ng-repeat="attr in product.category.templateAttribute">
<thead>
<tr>
<th colspan="4">{{attr.attribute}}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input value="{{attr.attribute}}" />
</td>
<td>
<input placeholder="name" ng-model="product.attributes[attr.attribute].name" />
</td>
<td>
<input placeholder="additional price" ng-model="product.attributes[attr.attribute].additionalPrice" />
</td>
<td rowspan="2">
<button type="button" ng-click="addItem(product.category.templateAttribute, attr)">
add
</button>
</td>
</tr>
<tr>
<td colspan="3">
<input type="file" class="form-control" ng-model="product.attributes[attr.attribute].file" />
</td>
</tr>
</tbody>
</table>
</body>
</html>
Codepen demo

Related

How to parent tr checked if child tr is checked

Info: I am try to make a nested table. The table have parent && child rows.
The feature
I want to make if user click on parent tr>input:checkbox the all child tr>input:checkbox checked.
I want to know if any parent-tr child-tr checkbox is checked then parent-tr also checked.
Parent tr automatically checked If user checked child input:checkbox checked one by one manually even if i checked only one. if under the parent child unchecked parents also unchecked.
function childRowCheck() {
const childRow = $("tr#child-tr input:checked")
childRow.each(function (i, item) {
let tbody = $(this).parents("tbody");
tbody.children("tr#parent-tr").eq(i).find(":checkbox").attr('checked', $(this).is(':checked'));
})
}
childRowCheck();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table class="table">
<tbody>
<!-- BEGIN::Subject loop -->
<tr id="parent-tr" class="parent-tr" data-id="2">
<td class="action">
<input type="checkbox" name="checkbox[2]" value="2" id="id_subject">
</td>
</tr>
<!-- END::Subject loop -->
<!-- BEGIN::Tickers loop -->
<tr id="child-tr" class="child-tr" data-ticker-id="6" data-subject-id="2">
<td class="action">
<input type="checkbox" name="tikcer" id="id_ticker">
</td>
</tr>
<tr id="child-tr" class="child-tr" data-ticker-id="7" data-subject-id="2">
<td class="action">
<input type="checkbox" name="tikcer" id="id_ticker">
</td>
</tr>
<tr id="child-tr" class="child-tr" data-ticker-id="8" data-subject-id="2">
<td class="action">
<input type="checkbox" name="tikcer" id="id_ticker">
</td>
</tr>
<!-- END::Tickers loop -->
<!-- BEGIN::Subject loop -->
<tr id="parent-tr" class="parent-tr" data-id="3">
<td class="action">
<input type="checkbox" name="checkbox[3]" value="3" id="id_subject">
</td>
<td colspan="6"></td>
</tr>
<!-- END::Subject loop -->
<!-- BEGIN::Tickers loop -->
<tr id="child-tr" class="child-tr" data-ticker-id="9" data-subject-id="3">
<td class="action">
<input type="checkbox" name="tikcer" id="id_ticker">
</td>
</tr>
<tr id="child-tr" class="child-tr" data-ticker-id="10" data-subject-id="3">
<td class="action">
<input type="checkbox" name="tikcer" id="id_ticker">
</td>
</tr>
<tr id="child-tr" class="child-tr" data-ticker-id="11" data-subject-id="3">
<td class="action">
<input type="checkbox" name="tikcer" id="id_ticker">
</td>
</tr>
<!-- END::Tickers loop -->
</tbody>
</table>
You have much better control of your application, if you control the data and not the UI:
create a data structure that best suits the relation(s) between the elements
create a template that can be re-used to populate the DOM
The main benefit of the solution below is that you always have a correct state that you can use (e.g. submit); also the shape of the data does not change: the input & output of your process look the same.
I put one more level of depth (so parent->child->grandchild) to show that it works quite nice with n levels hierarchy.
const data = [{
id: "parent-tr-1",
label: "Parent 1",
checked: false,
children: [{
id: "child-tr-1-1",
label: "Child 1_1",
checked: false,
children: [
{
id: "child-tr-1-1-1",
label: "Child 1_1_1",
checked: false,
children: [],
},
{
id: "child-tr-1-1-2",
label: "Child 1_1_2",
checked: false,
children: [],
}
],
},
{
id: "child-tr-1-2",
label: "Child 1_2",
checked: false,
children: [],
},
]
},
{
id: "parent-tr-2",
label: "Parent 2",
checked: false,
children: [{
id: "child-tr-2-1",
label: "Child 2_1",
checked: false,
children: [],
},
{
id: "child-tr-2-2",
label: "Child 2_2",
checked: false,
children: [],
},
{
id: "child-tr-2-3",
label: "Child 2_3",
checked: false,
children: [],
},
]
},
]
const getRowsFlat = (data) => data.reduce((a, c) => [...a, c, ...getRowsFlat(c.children)], [])
const setChecked = (id, data, checkedState) => {
data.forEach(e => {
// setting children checked if parent is clicked
if (e.id === id || id === "parent-force") {
e.checked = checkedState ?? !e.checked
if (e.id === id) {
setChecked("parent-force", e.children, e.checked)
} else {
setChecked("parent-force", e.children)
}
} else {
setChecked(id, e.children)
}
// if ANY of the children is set to checked, parent should be checked
if (e.children.length && e.children.some(({
checked
}) => checked)) {
e.checked = true
}
// if NONE of the children is set to checked, parent should not be checked
if (e.children.length && e.children.every(({
checked
}) => !checked)) {
e.checked = false
}
})
}
// row HTML template
const getRowHtml = (data) => {
return `
<tr>
<td>
<input type="checkbox" id="${data.id}" ${ data.checked ? "checked" : null }/>
<label for="${data.id}">${data.label}</label>
</td>
</tr>
`
}
// table update function
const updateContainer = (container) => (data) => {
container.innerHTML = data.map(getRowHtml).join("")
}
// initialization
const tbody = document.getElementById("tbody")
const updateTableBody = updateContainer(tbody)
// first render
setChecked(null, data) // if run with id NULL, then only the children can affect the parent
updateTableBody(getRowsFlat(data))
jQuery(document).ready(function($) {
$("#table").on("click", "input", function() {
const thisId = $(this).attr("id")
setChecked(thisId, data)
updateTableBody(getRowsFlat(data))
})
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table id="table">
<tbody id="tbody"></tbody>
</table>
You can not use the same id multiple times.
Check following code with class instead of id:
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tbody>
<!-- parent -->
<tr>
<td>
<input type="checkbox" name="subject" class="subject1" />Parent
</td>
<td colspan="3"></td>
</tr>
<!-- child -->
<tr>
<td><input type="checkbox" name="ticker" class="ticker1" />Child</td>
</tr>
<tr>
<td><input type="checkbox" name="ticker" class="ticker1" />Child</td>
</tr>
<tr>
<td><input type="checkbox" name="ticker" class="ticker1" />Child</td>
</tr>
<!-- parent -->
<tr>
<td>
<input type="checkbox" name="subject" class="subject2" />Parent
</td>
<td colspan="3"></td>
</tr>
<!-- child -->
<tr>
<td><input type="checkbox" name="ticker" class="ticker2" />Child</td>
</tr>
<tr>
<td><input type="checkbox" name="ticker" class="ticker2" />Child</td>
</tr>
<tr>
<td><input type="checkbox" name="ticker" class="ticker2" />Child</td>
</tr>
</tbody>
</table>
<script>
$(document).ready(function () {
$(".ticker1").click(function () {
if ($(this).is(":checked")) {
$(".subject1").prop("checked", true);
} else {
$(".subject1").prop("checked", false);
}
});
$(".ticker2").click(function () {
if ($(this).is(":checked")) {
$(".subject2").prop("checked", true);
} else {
$(".subject2").prop("checked", false);
}
});
});
</script>
Here I modified the code by changing ids to classes and made other necessary changes.

Keys in object are getting removed when i am using ng-repeat

i am using angular ng-repeat to add the set of input values which can be used to give the input.
how i am adding dynamically is i am taking an object and pushing into the ng-repeat variable. In the html each key in the object has a input field
javascript
(function () {
'use strict';
angular.module('myFirstApp', [])
.controller('MyFirstController', function ($scope) {
var flowchart=this;
$scope.conditionslv = [];
flowchart.field1dropdown = [{"FieldName":"","DisplayName":"select"},{"FieldName":"se","DisplayName":"se"},{"qw":"","DisplayName":"qw"}]
flowchart.operatordropdown = [{"OperatorTypeId":'',"OperatorTypeName":"select","WFSubConditions":[]},{"OperatorTypeId":1,"OperatorTypeName":"Greater Than","WFSubConditions":[]}]
flowchart.addconditionrow = function () {
$scope.conditionslv.push({
expression1: '', operatortypeid: '', expressionvalue: "", expression2value: "", comments: ""
});
console.log(JSON.stringify($scope.conditionslv));
}
flowchart.cancelConditons = function () {
flowchart.diagramshow = true;
flowchart.conditions = false;
}
flowchart.saveconditions=function(){
}
});
})();
html
<table>
<th>Field-1</th>
<th>Operator</th>
<th>Field-2</th>
<th>Comments</th>
<tbody>
<tr ng-repeat="i in conditionslv">
<td>{{i}}</td>
<td>
<select ng-model="i.expression1" required>
<option ng-repeat="item in fc.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<select ng-model="i.operatortypeid" ng-required="true" ng-options="item.OperatorTypeId as item.OperatorTypeName for item in fc.operatordropdown" ></select>
</td>
<td>
<input type="text" ng-model="i.expressionvalue" ng-disabled="i.expression2value!=''||i.operatortypeid>5" >/<select ng-model="i.expression2value" ng-disabled="i.expressionvalue!=''||i.operatortypeid>5" required>
<option ng-repeat="item in fc.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<textarea rows="1" cols="40" ng-model="i.comments"></textarea><span ng-click="conditionslv.splice($index,1)"
ng-if="conditionslv.length>1"><span class="k-icon k-font-icon k-i-x"></span></span>
</td>
</tr>
</tbody>
</table>
most of the inputs that i am adding are the dropdowns.
the problem is if i select a dropdown value and then again selecting the select option then the key corresponding to the dropdown is getting removed from the object
how the key is getting removed?thanks in advance
This may helpful..
(function () {
'use strict';
angular.module('myFirstApp', [])
.controller('MyFirstController', function ($scope) {
var flowchart=this;
flowchart.conditionslv = [{expression1: '', operatortypeid: '', expressionvalue: "", expression2value: "", comments: ""
}];
flowchart.field1dropdown = [{"FieldName":"ff","DisplayName":"select"},{"FieldName":"se","DisplayName":"se"},{"qw":"","DisplayName":"qw"}]
flowchart.operatordropdown = [{"OperatorTypeId":'',"OperatorTypeName":"select","WFSubConditions":[]},{"OperatorTypeId":1,"OperatorTypeName":"Greater Than","WFSubConditions":[]}]
flowchart.addconditionrow = function (valid) {
if(valid){
flowchart.conditionslv.push({
expression1: '', operatortypeid: '', expressionvalue: "", expression2value: "", comments: ""
});
} console.log(valid);
}
flowchart.cancelConditons = function () {
flowchart.diagramshow = true;
flowchart.conditions = false;
}
flowchart.saveconditions=function(){
}
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myFirstApp" ng-controller="MyFirstController as ctrl">
<form name="addForm" novalidate>
<button ng-click="ctrl.addconditionrow(addForm.$valid)" ng-disabled="addForm.$invalid">Add row</button>
<table>
<th>Field-1</th>
<th>Operator</th>
<th>Field-2</th>
<th>Comments</th>
<tbody>
<tr ng-repeat="i in ctrl.conditionslv">
<td>{{i.expression1}}{{i.operatortypeid}}{{i.expressionvalue}}{{i.expression2value}}{{i.comments}}</td>
<td>
<select ng-model="i.expression1" name="expre" required>
<option ng-repeat="item in ctrl.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<select ng-model="i.operatortypeid" ng-required="true" ng-options="item.OperatorTypeId as item.OperatorTypeName for item in ctrl.operatordropdown" ></select>
</td>
<td>
<input type="text" ng-model="i.expressionvalue" ng-disabled="i.expression2value!=''||i.operatortypeid>5" >/<select ng-model="i.expression2value" ng-disabled="" ng-required="i.expressionvalue!=''||i.operatortypeid>5 && i.expression2value==''">
<option ng-repeat="item in ctrl.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<textarea style="width:100px" rows="1" cols="40" ng-model="i.comments" name="comment" required></textarea>
<span ng-click="ctrl.conditionslv.splice($index,1)" ng-if="ctrl.conditionslv.length>1">
<span class="k-icon k-font-icon k-i-x"></span></span>
</td>
</tr>
</tbody>
</table>
</form>
</body>
Working jsfiddle
HTML
<table ng-controller="MyFirstController as fc">
<thead>
<th>Field-1</th>
<th>Operator</th>
<th>Field-2</th>
<th>Comments</th>
</thead>
<tbody>
<tr ng-repeat="i in conditionslv">
<td>
<select ng-model="i.expression1" required>
<option ng-repeat="item in fc.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<select ng-model="i.operatortypeid" ng-required="true" ng-options="item.OperatorTypeId as item.OperatorTypeName for item in fc.operatordropdown"></select>
</td>
<td>
<input type="text" ng-model="i.expressionvalue" ng-disabled="i.expression2value!=''||i.operatortypeid>5">/
<select ng-model="i.expression2value" ng-disabled="i.expressionvalue!=''||i.operatortypeid>5" required>
<option ng-repeat="item in fc.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<textarea rows="1" cols="40" ng-model="i.comments"></textarea><span ng-click="conditionslv.splice($index,1)" ng-if="conditionslv.length>1"><span class="k-icon k-font-icon k-i-x"></span></span>
</td>
</tr>
</tbody>
</table>
Controller
angular.module('myFirstApp', [])
.controller('MyFirstController', function($scope) {
var flowchart = this;
$scope.conditionslv = [];
flowchart.field1dropdown = [{
"FieldName": "",
"DisplayName": "select"
}, {
"FieldName": "se",
"DisplayName": "se"
}, {
"qw": "",
"DisplayName": "qw"
}];
flowchart.operatordropdown = [{
"OperatorTypeId": '',
"OperatorTypeName": "select",
"WFSubConditions": []
}, {
"OperatorTypeId": 1,
"OperatorTypeName": "Greater Than",
"WFSubConditions": []
}];
flowchart.addconditionrow = function() {
$scope.conditionslv.push({
expression1: '',
operatortypeid: '',
expressionvalue: "",
expression2value: "",
comments: ""
});
console.log(JSON.stringify($scope.conditionslv));
}
flowchart.cancelConditons = function() {
flowchart.diagramshow = true;
flowchart.conditions = false;
}
flowchart.saveconditions = function() {
}
flowchart.addconditionrow();
});
Need some clarifications :
From where this flowchart.addconditionrow() is executing ?
As you are pushing the single object into $scope.conditionslv array then why are you using ng-repeat ?. you can directly assign object property into the ng-model.
DEMO
angular.module('myApp', [])
.controller('MainController', function($scope) {
var flowchart = this;
$scope.conditionslv = [];
flowchart.field1dropdown = [{
"FieldName": "",
"DisplayName": "select"
}, {
"FieldName": "se",
"DisplayName": "se"
}, {
"qw": "",
"DisplayName": "qw"
}]
flowchart.operatordropdown = [{
"OperatorTypeId": '',
"OperatorTypeName": "select",
"WFSubConditions": []
}, {
"OperatorTypeId": 1,
"OperatorTypeName": "Greater Than",
"WFSubConditions": []
}]
flowchart.addconditionrow = function() {
$scope.conditionslv.push({
expression1: '',
operatortypeid: '',
expressionvalue: "",
expression2value: "",
comments: ""
});
}
flowchart.addconditionrow();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainController as fc">
<table>
<th>Field-1</th>
<th>Operator</th>
<th>Field-2</th>
<th>Comments</th>
<tbody>
<tr ng-repeat="i in conditionslv">
<td>
<select ng-model="i.expression1" required>
<option ng-repeat="item in fc.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<select ng-model="i.operatortypeid" ng-required="true" ng-options="item.OperatorTypeId as item.OperatorTypeName for item in fc.operatordropdown" ></select>
</td>
<td>
<input type="text" ng-model="i.expressionvalue" ng-disabled="i.expression2value!=''||i.operatortypeid>5" >/<select ng-model="i.expression2value" ng-disabled="i.expressionvalue!=''||i.operatortypeid>5" required>
<option ng-repeat="item in fc.field1dropdown" value="{{item.FieldName}}">{{item.DisplayName}}</option>
</select>
</td>
<td>
<textarea rows="1" cols="40" ng-model="i.comments"></textarea><span ng-click="conditionslv.splice($index,1)"
ng-if="conditionslv.length>1"><span class="k-icon k-font-icon k-i-x"></span></span>
</td>
</tr>
</tbody>
</table>
<div>

How to use submit button to search the record in a table?

Here is my index.html page
------index.html-------
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.4.0-beta.6" data-semver="1.4.0-beta.6"
src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
<script src="script.js"></script>
</head>
<body>
<div ng-app="myApp" ng-controller="PeopleCtrl"> <input type="text"
name="search1" >
<input type="submit" ng-model="search1" value="search"
ng-click="checkAll"> <table border="1" ng-init="ageToShow=(people|
underTwenty: 20).length >= 1">
<tr name="search1" > <th>Id</th> <th>Name</th> <th ng-show="ageToShow"
ng-if="!ageToShow">Age</th> </tr> <tr ng-repeat="person in
people|filter: search" ng-show="person.age>20" >
<td><span>{{person.id}}</span> </td> <td><span>{{person.name}}</span>
</td> <td ng-show="!ageToShow"><span>{{person.age}}</span> </td> </tr>
</table>
</div> </body> </html>
What i need is to use submit button to search the record .... And here is my script.js file...
--------script.js--------
// Code goes here
var myApp = angular.module('myApp', []);
myApp.controller('PeopleCtrl', function($scope,$filter) {
$scope.people = ([{
id: 1,
name: "Peter",
age: 22 }, {
id: 2,
name: "David",
age: 12 }, {
id: 3,
name: "Anil",
age: 32 }, {
id: 4,
name: "Chean",
age: 22 }, {
id: 5,
name: "Niladri",
age: 18 }
]);
$scope.people3 = $scope.people;
$scope.$watch('search1', function(val)
{
$scope.people = $filter('filter')($scope.people3, val);
});
}); myApp.filter('underTwenty', function() {
return function(values, limit) {
var returnValue = [];
angular.forEach(values, function(val, ind) {
if (val.age < limit)
returnValue.push(val);
}); return returnValue; }; });
And here goes my coding in plunker: http://plnkr.co/edit/?p=preview
Only for filtering if you are planning to do submit the form, then I'll suggest you to don't prefer form submit.
Form getting the same requirement done I'd create one dummy field for search text-box & then I'd assign that would to search model which we using for filter on click of search ng-click="search = search1"
HTML
<input type="text" name="search1" ng-model="search1"/>
<input type="button" value="search" ng-click="search = search1">
<table border="1" ng-init="ageToShow=(people| underTwenty: 20).length >= 1">
<tr name="search1">
<th>Id</th>
<th>Name</th>
<th ng-show="ageToShow" ng-if="!ageToShow">Age</th>
</tr>
<tr ng-repeat="person in people|filter: search" ng-show="person.age>20">
<td><span>{{person.id}}</span>
</td>
<td><span>{{person.name}}</span>
</td>
<td ng-show="!ageToShow"><span>{{person.age}}</span>
</td>
</tr>
</table>
& Do remove the watch from search1 variable. So the filtering will not occur on change of search1
Working Plunkr

Combine two Knockout Examples

I am trying to get two examples from knockout.com working and I have yet to figure it out. Any help would be greatly appreciated!
http://jsfiddle.net/gZC5k/2863/
When running this project and using a debugger I get an error:
Uncaught ReferenceError: Unable to process binding "foreach: function (){return linesa }"
Message: linesa is not defined
From the original example I changed lines to linesa to see if anything else was screwing it up. It still did not like linesa
My main goal is to get these two samples working together. The Add a contact button works but the Add product does not work.
Thank you!
<div class='liveExample'>
<h2>Contacts</h2>
<div id='contactsList'>
<table class='contactsEditor'>
<tr>
<th>First name</th>
<th>Last name</th>
<th>Phone numbers</th>
</tr>
<tbody data-bind="foreach: contactsa">
<tr>
<td>
<input data-bind='value: firstName' />
<div><a href='#' data-bind='click: $root.removeContact'>Delete</a></div>
</td>
<td><input data-bind='value: lastName' /></td>
<td>
<table>
<tbody data-bind="foreach: phones">
<tr>
<td><input data-bind='value: type' /></td>
<td><input data-bind='value: number' /></td>
<td><a href='#' data-bind='click: $root.removePhone'>Delete</a></td>
</tr>
</tbody>
</table>
<a href='#' data-bind='click: $root.addPhone'>Add number</a>
</td>
</tr>
</tbody>
</table>
</div>
<p>
<button data-bind='click: addContact'>Add a contact</button>
<button data-bind='click: save, enable: contactsa().length > 0'>Save to JSON</button>
</p>
<textarea data-bind='value: lastSavedJson' rows='5' cols='60' disabled='disabled'> </textarea>
</div>
<div class='liveExample'>
<table width='100%'>
<thead>
<tr>
<th width='25%'>Category</th>
<th width='25%'>Product</th>
<th class='price' width='15%'>Price</th>
<th class='quantity' width='10%'>Quantity</th>
<th class='price' width='15%'>Subtotal</th>
<th width='10%'> </th>
</tr>
</thead>
<tbody data-bind='foreach: linesa'>
<tr>
<td>
<select data-bind='options: sampleProductCategories, optionsText: "name", optionsCaption: "Select...", value: category'> </select>
</td>
<td data-bind="with: category">
<select data-bind='options: products, optionsText: "name", optionsCaption: "Select...", value: $parent.product'> </select>
</td>
<td class='price' data-bind='with: product'>
<span data-bind='text: formatCurrency(price)'> </span>
</td>
<td class='quantity'>
<input data-bind='visible: product, value: quantity, valueUpdate: "afterkeydown"' />
</td>
<td class='price'>
<span data-bind='visible: product, text: formatCurrency(subtotal())' > </span>
</td>
<td>
<a href='#' data-bind='click: $parent.removeLine'>Remove</a>
</td>
</tr>
</tbody>
</table>
<p class='grandTotal'>
Total value: <span data-bind='text: formatCurrency(grandTotal())'> </span>
</p>
<button data-bind='click: addLine'>Add product</button>
<button data-bind='click: save'>Submit order</button>
</div>
var initialData = [
{ firstName: "Danny", lastName: "LaRusso", phones: [
{ type: "Mobile", number: "(555) 121-2121" },
{ type: "Home", number: "(555) 123-4567"}]
},
{ firstName: "Sensei", lastName: "Miyagi", phones: [
{ type: "Mobile", number: "(555) 444-2222" },
{ type: "Home", number: "(555) 999-1212"}]
}
];
var ContactsModel = function(contactstest) {
var self = this;
self.contactsa = ko.observableArray(ko.utils.arrayMap(contactstest, function(contact) {
return { firstName: contact.firstName, lastName: contact.lastName, phones: ko.observableArray(contact.phones) };
}));
self.addContact = function() {
self.contactsa.push({
firstName: "",
lastName: "",
phones: ko.observableArray()
});
};
self.removeContact = function(contact) {
self.contactsa.remove(contact);
};
self.addPhone = function(contact) {
contact.phones.push({
type: "",
number: ""
});
};
self.removePhone = function(phone) {
$.each(self.contactsa(), function() { this.phones.remove(phone) })
};
self.save = function() {
self.lastSavedJson(JSON.stringify(ko.toJS(self.contactsa), null, 2));
};
self.lastSavedJson = ko.observable("")
};
ko.applyBindings(new ContactsModel(initialData));
function formatCurrency(value) {
return "$" + value.toFixed(2);
}
var CartLine = function() {
var self = this;
self.category = ko.observable();
self.product = ko.observable();
self.quantity = ko.observable(1);
self.subtotal = ko.computed(function() {
return self.product() ? self.product().price * parseInt("0" + self.quantity(), 10) : 0;
});
// Whenever the category changes, reset the product selection
self.category.subscribe(function() {
self.product(undefined);
});
};
var Cart = function() {
// Stores an array of lines, and from these, can work out the grandTotal
var self = this;
self.linesa = ko.observableArray([new CartLine()]); // Put one line in by default
self.grandTotal = ko.computed(function() {
var total = 0;
$.each(self.linesa(), function() { total += this.subtotal() })
return total;
});
// Operations
self.addLine = function() { self.linesa.push(new CartLine()) };
self.removeLine = function(line) { self.linesa.remove(line) };
self.save = function() {
var dataToSave = $.map(self.linesa(), function(line) {
return line.product() ? {
productName: line.product().name,
quantity: line.quantity()
} : undefined
});
alert("Could now send this to server: " + JSON.stringify(dataToSave));
};
};
ko.applyBindings(new Cart());
ViewModel is a ContactsModel, since ContactsModel does not have a linesa property, it cannot render the contents of the table.
<tbody data-bind='foreach: linesa'>
this is the offending line.
You are working with 2 ViewModels actually, the Cart ViewModel and the Contacts ViewModel.
you need to make a new ViewModel that implements both ViewModels and you can bind the views using with binding.
Code:
function CombinedViewModel(){
this.cart=new Cart();
this.contact=new Contact();
}
ko.appyBindings(new CombinedViewModel());
and for the bindings
<div data-bind="with:cart"><!-- cart html view goes here --></div>
<div data-bind="with:contact"><!-- contact html view goes here --></div>

Differentiating current textbox value from old one and showing in Angular JS

My code is like this
<body>
<div>
<table ng-app='myApp' ng-controller="MainCtrl">
<thead></thead>
<tbody ng-repeat="prdElement in palletElement track by $index">
<tr>
<td>{{prdElement.name}}</td>
</tr>
<tr ng-repeat="data in prdElement.Data">
<td>{{data.itemId}}</td>
<td>{{data.shipmentId}}</td>
<td>{{data.itemCode}}</td>
<td>{{data.description}}</td>
<td>{{data.handlingUnit}}</td>
<td>{{data.weight}}</td>
<td>{{data.class}}</td>
<td>{{data.lenght}}</td>
<td>{{data.width}}</td>
<td>{{data.height}}</td>
<td>{{data.flag}}</td>
<td>
<input type="text" ng-model="data.quantity" placeholder=" Code" required />
</td>
</tr>
<tr>
<td>
<button ng-click="newPalletItem( prdElement,$event)">Submit</button>
</td>
</tr>
<!--<tr id="displayitems" >
<td>
{{palletElement}}
</td>
</tr>-->
</tbody>
</table>
</div>
(function () {
angular.module('myApp', []).controller('MainCtrl', function ($scope) {
var counter = 0;
$scope.palletElement = [{
name: 'Pallet 1',
Data: [{
name: 'item 1',
itemId: '284307',
shipmentId: 'eb44f690-c97a-40e3-be2a-0449559e171a',
itemCode: '',
description: 'Bicycle parts - frame',
quantity: '31',
handlingUnit: 'CTN',
weight: '613.04',
class: '',
lenght: '102',
width: '42',
height: '61',
flag: 'P'
}, {
name: 'item 2',
itemId: '284308',
shipmentId: 'eb44f690-c97a-40e3-be2a-0449559e171a',
itemCode: '',
description: 'Bicycle parts - fork',
quantity: '22',
handlingUnit: 'CTN',
weight: '242.99',
class: '',
lenght: '75',
width: '34',
height: '18',
flag: 'P'
}]
}]
$scope.newPalletItem = function (palletElement, $event) {
counter++;
$scope.palletElement.push(palletElement);
}
});
}());
When some one changes the value in last column textbox and press submit button I want to calculate [preloded value in textbox - (minus) current value in that text box ] and show it in next row. So far I have managed to duplicate the entire data completely to next row. but have no Idea in how to achieve rest. Can any one pint out a solution.
Fiddle
More details from Fiddle: as you can see current value is first text box is 31 if some one changes it to 10 when I duplicate the row to bottom I want that new textbox value to be shown as 21 (which is 31-10).
Please see here: http://jsfiddle.net/8r8cxcup/
newPalletImte:
$scope.newPalletItem = function (palletElement, $event) {
var npalletElement = {};
angular.copy(palletElement, npalletElement);
counter++;
angular.forEach(npalletElement.Data, function (row) {
if (row.quantity != row.newquantity) {
row.quantity = row.quantity - row.newquantity;
}
});
$scope.palletElement.push(npalletElement);
};
});
HTML:
<table ng-app='myApp' ng-controller="MainCtrl">
<thead></thead>
<tbody ng-repeat="prdElement in palletElement track by $index">
<tr>
<td>{{prdElement.name}}</td>
</tr>
<tr ng-repeat="data in prdElement.Data" ng-init="data.newquantity = data.quantity">
<td>{{data.itemId}}</td>
<td>{{data.shipmentId}}</td>
<td>{{data.itemCode}}</td>
<td>{{data.description}}</td>
<td>{{data.handlingUnit}}</td>
<td>{{data.weight}}</td>
<td>{{data.class}}</td>
<td>{{data.lenght}}</td>
<td>{{data.width}}</td>
<td>{{data.height}}</td>
<td>{{data.flag}}</td>
<td>
<input type="text" ng-model="data.newquantity" placeholder=" Code" required />
</td>
</tr>
<tr>
<td>
<button ng-click="newPalletItem( prdElement,$event)">Submit</button>
</td>
</tr>
<!--<tr id="displayitems">
<td>
{{palletElement}}
</td>
</tr>-->
</tbody>
</table>

Categories

Resources