AngularJS model update reverting back to original - angularjs

http://plnkr.co/edit/3UMwSK6H5VL0pZujL7Qh?p=preview
Click edit and then cancel. The text boxes do not go away. Click cancel again, they go away. Please tell me why this is happening. I am losing my mind over this.
Thanks is advance. :)
Here is the code:
function SmartTableController($scope) {
$scope.sortFunc = function (keyname) {
$scope.sortType = keyname;
$scope.reverse = !$scope.reverse;
}
$scope.editing = false;
$scope.newField = {};
$scope.editUsersTableFunc = function (user) {
user.editing = true;
$scope.newField = angular.copy(user);
$scope.editing = $scope.usersTable.indexOf(user);
}
$scope.saveField = function (user) {
user.editing = false;
$scope.newField = angular.copy(user);
$scope.usersTable[$scope.editing] = $scope.newField;
}
$scope.resetFunc = function (user) {
//$scope.newField = angular.copy(user);
user.editing = false;
$scope.usersTable[$scope.editing] = $scope.newField;
}
var OnEventChangeFunc = function () {
$scope.lastItem = $scope.currentPage * $scope.itemsDisplayedPerPage;
$scope.firstItem = $scope.lastItem - $scope.itemsDisplayedPerPage + 1;
$scope.lastItem = $scope.lastItem > $scope.totalRecords ? $scope.totalRecords : $scope.lastItem;
}
$scope.itemsDisplayedPerPage = '5';
$scope.currentPage = 1;
$scope.$watch('itemsDisplayedPerPage', OnEventChangeFunc);
$scope.$watch('currentPage', OnEventChangeFunc);
$scope.usersTable =[{ firstName: "a", lastName: "b", emailId: "abc#efg.com", country: "US" },
{ firstName: "a", lastName: "b", emailId: "abc#efg.com", country: "US" },
{ firstName: "a", lastName: "b", emailId: "abc#efg.com", country: "US" }];
$scope.totalRecords = $scope.usersTable.length;
}
SmartTableController.$inject = ['$scope'];
angular.module('smartTable', ['angularUtils.directives.dirPagination']);
angular.module('smartTable').controller('SmartTableController', SmartTableController);
<!DOCTYPE html>
<html ng-app="smartTable">
<head>
<title></title>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-smart-table/2.1.8/smart-table.js"></script>
<script src="dirPagination.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="SmartTableController">
<div class="form-inline">
<label>Search : </label>
<input type="search" ng-model="search" class="form-control" placeholder="Enter text to search" />
</div>
<div st-table="usersTable">
<table class="table table-striped">
<thead>
<tr>
<th>Index</th>
<!--<th > First Name</th>-->
<th>
<a href="#" ng-click="sortFunc('firstName')">
First Name
</a>
</th>
<!--<th ng-click="sortType='lastName'"> Last Name</th>-->
<th>
<a href="#" ng-click="sortFunc('lastName')">
Last Name
</a>
</th>
<!--<th ng-click="sortType='emailId'"> Email Id</th>-->
<th>
<a href="#" ng-click="sortFunc('emailId')">
Email Id
</a>
</th>
<!--<th ng-click="sortType='country'"> Country</th>-->
<th>
<a href="#" ng-click="sortFunc('country')">
Country
</a>
</th>
</tr>
</thead>
<tbody>
<tr dir-paginate="user in usersTable | orderBy : sortType : reverse| filter : search | itemsPerPage : itemsDisplayedPerPage" current-page="currentPage">
<td>
{{$index + firstItem}}</td>
<td>
<input type="text" ng-if="user.editing" ng-model="user.firstName"/>
<span ng-if="!user.editing">{{user.firstName}}</span></td>
<td>
<input type="text" ng-if="user.editing" ng-model="user.lastName"/>
<span ng-if="!user.editing">{{user.lastName}}</span></td>
<td>
<input type="text" ng-if="user.editing" ng-model="user.emailId"/>
<span ng-if="!user.editing">{{user.emailId}}</span></td>
<td>
<input type="text" ng-if="user.editing" ng-model="user.country"/>
<span ng-if="!user.editing">{{user.country}}</span></
<td><input type="button" ng-if="!user.editing" class="btn btn-primary" ng-click="editUsersTableFunc(user)" value="Edit"/>
<input type="submit" ng-if="user.editing" ng-click="saveField(user)" value="Save" class="btn btn-primary" />
<input type="submit" ng-if="user.editing" ng-click="resetFunc(user);" value="Cancel" class="btn btn-primary" /></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

So here's what's going on:
1) When you click on "Edit" button it triggers $scope.editUsersTableFunc(user). Here when you pass user as a parameter, you actually pass element of your $scope.usersTable. This is because of dir-paginate="user in usersTable" in index.html. So in editUsersTableFunc() function user equals to $scope.usersTable[$scope.editing] or equals to {firstName: "a", lastName: "b", emailId: "abc#efg.com", country: "US"} in other words. At first line in this function you write user.editing = true; and thereby now $scope.usersTable[$scope.editing] = {firstName: "a", lastName: "b", emailId: "abc#efg.com", country: "US", editing: true}. Note here is new property editing: true. At the next step you save THIS user in $scope.newField (copy it).
Are you still following?=)
2) Now when you click on "Cancel" button, $scope.resetFunc() triggers. You also pass user here. Which now has property editing: true (user.editing === true). Then you write user.editing = false. Yes, now inputs have to disappear...but! right after that you reassign your user via next line: $scope.usersTable[$scope.editing] = $scope.newField;. Yep, and now again user.editing is equal to true (so it is shown), because $scope.newField contain user with property editing: true.
3) When you click on "Cancel" second time, you pass new user as the parameter. You actually pass $scope.usersTable[$scope.editing] and in the end of step 2) it became $scope.newField. So now when you write user.editing = false you do $scope.newField.editing = false. And it works.
Hope you get it =)
Here is my plunker example on how you can fix it. I only changed resetFunc:
$scope.resetFunc = function (user) {
$scope.newField.editing = false;
$scope.usersTable[$scope.editing] = $scope.newField;
}

Related

Push empty row with input field using angularjs

I have one table which have edit, delete and add options. My problem is when I click on add button want to add row with empty input fields. I have write below code for this. What should I do to add empty row with empty input values.
My code
<div ng-controller="AppKeysCtrl">
<button ng-click="add()">
Add
</button>
<table class="table table-hover mytable">
<thead>
<tr>
<th></th>
<th>Created</th>
<th>App Key</th>
<th>Name</th>
<th>Level</th>
http://jsfiddle.net/Thw8n/155/#update <th>Active</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="entry in appkeys" data-ng-class="{danger:!entry.active}">
<td>{{$index + 1}}</td>
<td>{{entry.timestamp | date:'mediumDate'}}</td>
<td>{{entry.appkey}}</td>
<td>
<span data-ng-hide="editMode">{{entry.name}}</span>
<input type="text" data-ng-show="editMode" data-ng-model="entry.name" data-ng-required />
</td>
<td>
<span data-ng-hide="editMode">{{entry.level}}</span>
<select class="form-control" name="entry.level" data-ng-model="entry.level" data-ng-show="editMode">
<option value="3">3 - Developer Access - [Temporary]</option>
<option value="2">2 - Standard Tool Access - [Default]</option>
<option value="1">1 - Administrative Access - [Admin Section Only]</option>
</select>
</td>
<td>
<span data-ng-hide="editMode">{{entry.active && 'Active' || 'Inactive'}}</span>
<select class="form-control" name="entry.active" data-ng-model="entry.active" data-ng-show="editMode">
<option value="true">Active</option>
<option value="false">Inactive</option>
</select>
</td>
<td>
<button type="submit" data-ng-hide="editMode" data-ng-click="editMode = true; editAppKey(entry)" class="btn btn-default">Edit</button>
<button type="submit" data-ng-show="editMode" data-ng-click="editMode = false" class="btn btn-default">Save</button>
<button type="submit" data-ng-show="editMode" data-ng-click="editMode = false; cancel($index)" class="btn btn-default">Cancel</button>
</td>
</tr>
</tbody>
</table>
<pre>newField: {{newField|json}}</pre></br></br>
<pre>appkeys: {{appkeys|json}}</pre>
</div>
app = angular.module("formDemo", []);
function AppKeysCtrl($scope, $http, $location) {
var tmpDate = new Date();
$scope.newField = [];
$scope.editing = false;
$scope.appkeys = [
{ "appkey" : "0123456789", "name" : "My new app key", "created" : tmpDate },
{ "appkey" : "abcdefghij", "name" : "Someone elses app key", "created" : tmpDate }
];
$scope.editAppKey = function(field) {
$scope.editing = $scope.appkeys.indexOf(field);
$scope.newField[$scope.editing] = angular.copy(field);
}
$scope.saveField = function(index) {
//if ($scope.editing !== false) {
$scope.appkeys[$scope.editing] = $scope.newField;
//$scope.editing = false;
//}
};
$scope.cancel = function(index) {
//if ($scope.editing !== false) {
$scope.appkeys[index] = $scope.newField[index];
$scope.editing = false;
//}
};
$scope.add = function () {
var entry = {};
//$scope.goals.push(goal);
$scope.appkeys.push(entry);
};
}
angular.element(document).ready(function() {
angular.bootstrap(document, ["formDemo"]);
});
I have problem in this that when I click on add empty row is adding which have form fields with ng-hide attribute. I want to add row dynamically with new input boxes for each column. What should I do for this? Please help.
It's quite simple. You need to push an object with blank value into your array.
Below is the code:
Controller
$scope.add = function () {
$scope.appkeys.push({appkey : '', name : '', created : '' });
};
The above code will only add a row. I have updated your JSFiddle for your desired output.
Please go through with the given link.
http://jsfiddle.net/Thw8n/570/
You need to paste the following code:
$scope.add = function () {
$scope.appkeys.push({appkey : '', name : '', created : '' });
};
You can push object with empty properties in your appkey array:
var tempObject = {
"appkey":"",
"name":"",
"created":""
};
$scope.appkeys.push(tempObject);

How to use an array on ng-model

This is my code http://plnkr.co/edit/oxtojjEPwkKng9iKkc14?p=preview
And I want to save object of sport and punctuation in an array, if there are one or more sports selected save it in the array like this:
likes[
{sport: 'futball', points: 1}, {sport: 'tennis', points: 1}
]
thanks!
You have to keep practicing your English a little bit more (you can ask me on the comment section in spanish if you are strugling)
I think what you are trying to do is to have a single select to be able to choose the sport and score,
Html:
<body ng-app="myapp">
<div class="main-container" ng-controller="main" ng-init="darr.dept=dept2">
<div class="client-area">
<label fo.table-container tabler="txt">Score</label>
<input type="text" id="name-txt" placeholder="Assign the score" ng-model="name">
<br />
Sport
<select ng-model="dept" ng-options="deptOpt.value as deptOpt.name for deptOpt in deptList"></select>
<br />
<button ng-click="add()">Add Item</button>
<table id="tab">
<thead>
<tr id="trow">
<th>Score</th>
<th>Sport</th>
<th>Options</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="ar in arr">
<td>{{ar.name}}</td>
<td>{{ar.dept}}</td>
<td>
<button ng-click="del($index)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
js:
var app = angular.module("myapp", []);
app.controller('main', function ($scope) {
$scope.arr = [];
$scope.deptList = [{
name: 'Football',
value: 'football'
}, {
name: 'Tennis',
value: 'Tennis'
}, {
name: 'Baseball',
value: 'baseball'
}];
$scope.dept = "football";
$scope.name = "";
$scope.add = function () {
this.arr.push({
name: this.name,
dept: this.dept
});
};
$scope.del = function (ind) {
this.arr = this.arr.splice(ind, 1);
};
$scope.editStudent = function(student) {
console.log(student);
};
});
https://jsfiddle.net/azweig/v5kbsudy/1

Angular: Uncaught ReferenceError: myFunction is not defined

I'm creating a contacts list and i'm using Angular for the first time.
I created an attribute directive for the table rows (that i use inside the table tag), in which i add a controller to handle click on a button, that deletes the row removing it from the table.
All works well, but i get an error in the browser console.
Here you can see the output of my source code:
When i try to delete a contact (i press on the button with the trash as icon) it works, but in the Chrome console i get this error:
Uncaught ReferenceError: delUser is not defined
You can see it here:
Here is my code:
index.html
<!doctype html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="utf-8">
<title>Rubrica</title>
<link rel="stylesheet" href="css/app.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</head>
<body ng-controller="myCtrl">
<section id="panel">
<button class="panel_btn" ng-click="showHideAdd()"><i class="fa fa-plus"></i> Aggiungi</button>
<button class="panel_btn" ng-click="showHideSearch()"><i class="fa fa-search"></i> Cerca</button>
</section>
<section id="list">
<table width="50%">
<thead>
<tr>
<th>Nome<span ng-show="sortType == 'name' && !sortReverse" class="fa fa-caret-down"></span><span ng-show="sortType == 'name' && sortReverse" class="fa fa-caret-up"></span></th>
<th>Cognome<span ng-show="sortType == 'surname' && !sortReverse" class="fa fa-caret-down"></span><span ng-show="sortType == 'surname' && sortReverse" class="fa fa-caret-up"></span></th>
<th>Telefono<span ng-show="sortType == 'phone' && !sortReverse" class="fa fa-caret-down"></span><span ng-show="sortType == 'phone' && sortReverse" class="fa fa-caret-up"></span></th>
<th>Operazioni</th>
</tr>
</thead>
<tbody>
<tr ng-hide="isSearchVisible">
<td><input name="nameSearch" placeholder="Cerca nome" ng-model="search.name"></input></td>
<td><input name="surnameSearch" placeholder="Cerca cognome" ng-model="search.surname"></input></td>
<td><input name="phoneSearch" placeholder="Cerca telefono" ng-model="search.phone"></input></td>
</tr>
<tr userdir item="user" onclick="delUser" ng-repeat="user in users | orderBy:sortType:sortReverse | filter:search">
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Totale utenti: {{getTotal()}}</td>
</tr>
</tfoot>
</table>
</section>
<section id="tools">
<form name="addForm" ng-show="isAddVisible" novalidate>
<p>Compila tutti i campi</p>
<input type="text" name="nameToAdd" placeholder="Nome" ng-model="formName" required ng-minlength="3"><br /><small ng-show="isInvalid && (addForm.nameToAdd.$error.required || addForm.nameToAdd.$error.minlength)">Il nome deve avere almeno 3 lettere</small><br />
<input type="text" name="surnameToAdd" placeholder="Cognome" ng-model="formSurname" required ng-minlength="3"><br /><small ng-show="isInvalid && (addForm.surnameToAdd.$error.required || addForm.surnameToAdd.$error.minlength)">Il cognome deve avere almeno 3 lettere</small><br />
<input type="tel" name="phoneToAdd" placeholder="Telefono" ng-model="formPhone" required ng-pattern="/^\d{2,4}/\d{5,8}/"><br /><small ng-show="isInvalid && (addForm.phoneToAdd.$error.required || addForm.phoneToAdd.$error.pattern)">Inserisci un numero di telefono valido</small><br />
<button ng-click="add()"><i class="fa fa-save fa-lg"></i> Salva</button>
</form>
<form name="searchForm" ng-submit="search()" ng-show="isSearchVisible" novalidate>
<p>Cerca utenti</p>
<input type="text" name="stringToFind" placeholder="Cerca..." ng-model="search.$" required><br />
</form>
</section>
</body>
</html>
app.js
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', ['$scope', '$timeout', function($scope, $timeout) {
$scope.sortType = 'name';
$scope.sortReverse = false;
$scope.isInvalid = false;
$scope.users = [{
name: 'Mario',
surname: 'Rossi',
phone: '084/8465645'
}, {
name: 'Giuseppe',
surname: 'Bianchi',
phone: '06/548484'
}, {
name: 'Luca',
surname: 'Verde',
phone: '0984/3214867'
}, {
name: 'Luigi',
surname: 'Roma',
phone: '0775/3214867'
}];
$scope.getTotal = function() {
return $scope.users.length;
};
$scope.add = function() {
if ($scope.addForm.$valid) {
$scope.users.push({
name: $scope.formName,
surname: $scope.formSurname,
phone: $scope.formPhone
});
$scope.formName = '';
$scope.formSurname = '';
$scope.formPhone = '';
} else {
$scope.isInvalid = true;
}
};
$scope.isAddVisible = false;
$scope.showHideAdd = function() {
$scope.isAddVisible = $scope.isAddVisible ? false : true;
$scope.isSearchVisible = false;
};
$scope.isSearchVisible = false;
$scope.showHideSearch = function() {
$scope.isSearchVisible = $scope.isSearchVisible ? false : true;
$scope.isAddVisible = false;
};
$scope.delUser = function(user) {
var index = $scope.users.indexOf(user);
$scope.users.splice(index, 1);
};
}]);
myApp.directive('userdir', function() {
return {
restrict: 'A',
templateUrl: 'views/userRow.html',
controller: function($scope) {
$scope.delete = function() {
$scope.onclick($scope.item);
};
},
controllerAs: 'ctrl',
scope: {
item: '=',
onclick: '='
}
};
});
userRow.html
<tr>
<td>{{item.name}}</td>
<td>{{item.surname}}</td>
<td>{{item.phone}}</td>
<td><button ng-click="delete()"><i class="fa fa-trash"></i></button>
</tr>
Renaming onclick to any other word inside my directive's scope makes it working.
The glitch may happen because onclick is a reserved word for HTML.
It looks like your "ng-click=delete()" already calls the delUser function.
Why do you need the onclick="delUser" in index.html?
Also if this a function should it be onclick="delUser()"?

ng-repeat with controller for each table row: how do I access x-editable form elements?

I setting up a scenario very similar to the Editable Row example from the x-editable demo site. In this scenario, a there is a simple table with three columns for data and a fourth for edit and delete buttons. A third button outside of the table adds a row to the table. When the form is editable, the data columns become editable (the primary feature of x-editable library). For this demo, the first column becomes a simple text edit and the second two columns become drop lists.
The table is created by having an ng-repeat on a row template. I need to do a few different things that all involve accessing the scope created by the ng-repeat. I need to
detect when the row is editable and when it is not
filter the options for the second drop list when the first drop list changes
In order to try to work with this demo, I've added a controller for the individual row. That has given me some access to the form (name = rowform), but I'm still not able to set a watch on the "make" property. I can't even find what property of the form is changing when the user makes a selection.
How do I set up a watch on the 'make' property?
Page Controller
angular.module('app').controller("quoteBuckingRaterController",
function ($scope, $q, $filter, listService, transactionDataService) {
$scope.equipment = [];
$scope.makes = [];
$scope.models = [];
$scope.showModel = function(equip) {
if(equip.model) {
var selected = $filter('filter')($scope.models, {id: equip.model});
return selected.length ? selected[0].name : 'Not set';
} else {
return 'Not set';
}
};
$scope.showMake = function(equip) {
if (equip.model) {
var selected = $filter('filter')($scope.models, { id: equip.model });
if (selected.length && selected.length > 0) {
if (equip.make != selected[0].make)
equip.make = selected[0].make;
return selected[0].make;
}
else {
return 'Not set';
}
} else {
return 'Not set';
}
};
$scope.checkName = function (data, id) {
if (!data) {
return "Description is required";
}
};
$scope.checkModel = function (data, id) {
if (!data) {
return "Model is required";
}
};
$scope.saveEquipment = function (data, id) {
$scope.inserted = null;
};
$scope.cancelRowEdit = function (data, id) {
$scope.inserted = null;
};
$scope.removeEquipment = function(index) {
$scope.equipment.splice(index, 1);
};
$scope.addEquipment = function() {
$scope.inserted = {
id: $scope.equipment.length+1,
name: '',
make: null,
model: null
};
$scope.equipment.push($scope.inserted);
};
$scope.filterModels = function (make) {
$scope.models = _.where($scope.allModels, function(item) {
return item.make == make;
});
};
//called by another process when page loads
$scope.initialize = function (loaded) {
return $q(function (resolve, reject) {
if (!loaded) {
listService.getEquipmentModels().then(function (data) {
$scope.allModels = data;
$scope.models = data;
//uses underscore.js
$scope.makes = _.chain(data)
.map(function (item) {
var m = {
id: item.make,
name: item.make
};
return m;
})
.uniq()
.value();
resolve();
});
}
});
}
});
Row Controller
angular.module('app').controller("editRowController",
function ($scope) {
$scope.testClick = function () {
alert('button clicked');
};
$scope.make = null;
$scope.$watch('make', function () {
alert('how do I tell when the make has been changed?');
this.$parent.$parent.filterModels(make.id);
});
});
HTML
<div>
<div class="col-md-12" style="margin-bottom: 3px">
<div class="col-md-4 col-md-offset-1" style="padding-top: 6px; padding-left: 0px"><label>Equipment</label></div>
<div class="col-md-offset-10">
<button class="btn btn-primary btn-sm" ng-click="addEquipment()">Add row</button>
</div>
</div>
<div class="col-md-10 col-md-offset-1">
<table class="table table-bordered table-hover table-condensed">
<tr style="font-weight: bold; background-color: lightblue">
<td style="width:35%">Name</td>
<td style="width:20%">Make</td>
<td style="width:20%">Model</td>
<td style="width:25%">Edit</td>
</tr>
<tr ng-repeat="equip in equipment" ng-controller="editRowController">
<td>
<!-- editable equip name (text with validation) -->
<span editable-text="equip.name" e-name="name" e-form="rowform" onbeforesave="checkName($data, equip.id)" e-required>
{{ equip.name || 'empty' }}
</span>
</td>
<td>
<!-- editable make (select-local) -->
<span editable-select="equip.make" e-name="make" e-form="rowform" e-ng-options="s.value as s.name for s in makes">
{{ showMake(equip) }}
</span>
</td>
<td>
<!-- editable model (select-remote) -->
<span editable-select="equip.model" e-name="model" e-form="rowform" e-ng-options="g.id as g.name for g in models" onbeforesave="checkModel($data, equip.id)" e-required>
{{ showModel(equip) }}
</span>
<button type="button" ng-disabled="rowform.$waiting" ng-click="testClick()" class="btn btn-default">
test
</button>
</td>
<td style="white-space: nowrap">
<!-- form -->
<form editable-form name="rowform" onbeforesave="saveEquipment($data, equip.id)" ng-show="rowform.$visible" class="form-buttons form-inline" shown="inserted == equip">
<button type="submit" ng-disabled="rowform.$waiting" class="btn btn-primary">
save
</button>
<button type="button" ng-disabled="rowform.$waiting" ng-click="rowform.$cancel()" class="btn btn-default">
cancel
</button>
</form>
<div class="buttons" ng-show="!rowform.$visible">
<button class="btn btn-primary" ng-click="rowform.$show()">edit</button>
<button class="btn btn-danger" ng-click="removeEquipment($index)">del</button>
</div>
</td>
</tr>
</table>
</div>
</div>
ng-repeat creates a child scope for each row (for each equipment). The scope of the EditRowController is therefore a childScope of the parent quoteBuckingRaterController.
This childScope contains:
all properties of the parent scope (e.g. equipment, makes, models)
the property equip with one value of the equipment array, provided by ng-repeat
any additional scope property that is defined inside the ng-repeat block, e.g. rowform
Therefore you are able to access these properties in the childController editRowController using the $scope variable, e.g.:
$scope.equip.make
$scope.equipment
and inside the ng-repeat element in the html file by using an angular expression, e.g:
{{equip.make}}
{{equipment}}
Now to $scope.$watch: If you provide a string as the first argument, this is an angular expression like in the html file, just without surrounding brackets {{}}. Example for equip.make:
$scope.$watch('equip.make', function (value) {
console.log('equip.make value (on save): ' + value);
});
However, angular-xeditable updates the value of equip.make only when the user saves the row. If you want to watch the user input live, you have to use the $data property in the rowform object, provided by angular-xeditable:
$scope.$watch('rowform.$data.make', function (value) {
console.log('equip.make value (live): ' + value);
}, true);
You can also use ng-change:
<span editable-select="equip.make" e-name="make" e-ng-change="onMakeValueChange($data)" e-form="rowform" e-ng-options="s.value as s.name for s in makes">
JS:
$scope.onMakeValueChange = function(newValue) {
console.log('equip.make value onChange: ' + newValue);
}
That should solve your first question: How to watch the make property.
Your second question, how to detect when the row is editable and when it is not, can be solved by using the onshow / onhide attributes on the form or by watching the $visible property of the rowform object in the scope as documented in the angular-xeditable reference
<form editable-form name="rowform" onshow="setEditable(true)" onhide="setEditable(false)">
$scope.setEditable = function(value) {
console.log('is editable? ' + value);
};
// or
$scope.$watch('rowform.$visible', function(value) {
console.log('is editable? ' + value);
});
You might ask why the rowform object is in the current childScope.
It is created by the <form> tag. See the Angular Reference about the built-in form directive:
Directive that instantiates FormController.
If the name attribute is specified, the form controller is published
onto the current scope under this name.
A working snippet with your example code:
angular.module('app', ["xeditable"]);
angular.module('app').controller("editRowController", function ($scope) {
$scope.testClick = function () {
alert('button clicked');
};
$scope.$watch('equip.make', function (value) {
console.log('equip.make value (after save): ' + value);
});
$scope.$watch('rowform.$data.make', function (value) {
console.log('equip.make value (live): ' + value);
}, true);
// detect if row is editable by using onshow / onhide on form element
$scope.setEditable = function(value) {
console.log('is equip id ' + $scope.equip.id + ' editable? [using onshow / onhide] ' + value);
};
// detect if row is editable by using a watcher on the form property $visible
$scope.$watch('rowform.$visible', function(value) {
console.log('is equip id ' + $scope.equip.id + ' editable [by watching form property]? ' + value);
});
});
angular.module('app').controller("quoteBuckingRaterController", function ($scope, $filter) {
$scope.equipment = [];
$scope.makes = [{value: 1, name: 'Horst'}, {value: 2, name: 'Fritz'}];
$scope.models = [{id: 1, name: 'PC', make: 1}];
$scope.showModel = function(equip) {
if(equip.model) {
var selected = $filter('filter')($scope.models, {id: equip.model});
return selected.length ? selected[0].name : 'Not set';
} else {
return 'Not set';
}
};
$scope.showMake = function(equip) {
if (equip.model) {
var selected = $filter('filter')($scope.models, { id: equip.model });
if (selected.length && selected.length > 0) {
if (equip.make != selected[0].make)
equip.make = selected[0].make;
return selected[0].make;
}
else {
return 'Not set';
}
} else {
return 'Not set';
}
};
$scope.checkName = function (data, id) {
if (!data) {
return "Description is required";
}
};
$scope.checkModel = function (data, id) {
if (!data) {
return "Model is required";
}
};
$scope.saveEquipment = function (data, id) {
$scope.inserted = null;
};
$scope.cancelRowEdit = function (data, id) {
$scope.inserted = null;
};
$scope.removeEquipment = function(index) {
$scope.equipment.splice(index, 1);
};
$scope.addEquipment = function() {
$scope.inserted = {
id: $scope.equipment.length+1,
name: '',
make: null,
model: null
};
$scope.equipment.push($scope.inserted);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-xeditable/0.1.9/js/xeditable.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-xeditable/0.1.9/css/xeditable.css" rel="stylesheet"/>
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<div ng-app="app" ng-controller="quoteBuckingRaterController">
<div class="col-md-12" style="margin-bottom: 3px">
<div class="col-md-4 col-md-offset-1" style="padding-top: 6px; padding-left: 0px"><label>Equipment</label></div>
<div class="col-md-offset-10">
<button class="btn btn-primary btn-sm" ng-click="addEquipment()">Add row</button>
</div>
</div>
<div class="col-md-10 col-md-offset-1">
<table class="table table-bordered table-hover table-condensed">
<tr style="font-weight: bold; background-color: lightblue">
<td style="width:35%">Name</td>
<td style="width:20%">Make</td>
<td style="width:20%">Model</td>
<td style="width:25%">Edit</td>
</tr>
<tr ng-repeat="equip in equipment" ng-controller="editRowController">
<td>
<!-- editable equip name (text with validation) -->
<span editable-text="equip.name" e-name="name" e-form="rowform" onbeforesave="checkName($data, equip.id)" e-required>
{{ equip.name || 'empty' }}
</span>
</td>
<td>
<!-- editable make (select-local) -->
<span editable-select="equip.make" e-name="make" e-form="rowform" e-ng-options="s.value as s.name for s in makes">
{{ showMake(equip) }}
</span>
</td>
<td>
<!-- editable model (select-remote) -->
<span editable-select="equip.model" e-name="model" e-form="rowform" e-ng-options="g.id as g.name for g in models" onbeforesave="checkModel($data, equip.id)" e-required>
{{ showModel(equip) }}
</span>
<button type="button" ng-disabled="rowform.$waiting" ng-click="testClick()" class="btn btn-default">
test
</button>
</td>
<td style="white-space: nowrap">
<!-- form -->
<form editable-form name="rowform" onbeforesave="saveEquipment($data, equip.id)" ng-show="rowform.$visible" class="form-buttons form-inline" shown="inserted == equip" onshow="setEditable(true)" onhide="setEditable(false)">
<button type="submit" ng-disabled="rowform.$waiting" class="btn btn-primary">
save
</button>
<button type="button" ng-disabled="rowform.$waiting" ng-click="rowform.$cancel()" class="btn btn-default">
cancel
</button>
</form>
<div class="buttons" ng-show="!rowform.$visible">
<button class="btn btn-primary" ng-click="rowform.$show()">edit</button>
<button class="btn btn-danger" ng-click="removeEquipment($index)">del</button>
</div>
</td>
</tr>
</table>
</div>
</div>
If you simply want to $watch the make property of equipment, try changing to:
$scope.$watch('equipment.make', function(){(...)})
You could write your own directive for this.
The main advantage is that directives have isolated scope and can have their own controller.
see the directive documentation to know if it's for you.

angularJS: Filter JSON Data w.r.t Date Range

I am completely new to AngularJS. Here is my HTML code
<div ng-controller="DateRangeCtrl">
<div class="container">
<div class="form-horizontal">
<input type="text" datepicker-popup="MM-dd-yyyy" ng-model="dt1" is-open="opened1" max="maxFromDate" ng-change="setMinToDate()"/>
<button class="btn btn-sm" ng-click="open1($event)"><span class="glyphicon glyphicon-calendar"></span></button>
</div>
<div class="form-horizontal">
<input type="text" datepicker-popup="MM-dd-yyyy" ng-model="dt2" is-open="opened2" min="minToDate" max="maxToDate" ng-change="filterDateAdded()"/>
<button class="btn btn-sm" ng-click="open2($event)"><span class="glyphicon glyphicon-calendar"></span></button>
</div>
<p><strong>Selected From Date: </strong> {{dt1 | date:'mediumDate'}}</p>
<p><strong>Selected To Date: </strong> {{dt2 | date:'mediumDate'}}</p>
</div>
<hr />
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Date Added</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items | orderBy:mySortFunction ">
<td>{{item.ID}}</td>
<td>{{ parseDate(item.dateAdded) | date:'longDate'}}</td>
</tr>
</tbody>
</table>
</div>
The following is my angular code:
testApp.config(function (datepickerConfig, datepickerPopupConfig) {
datepickerConfig.showWeeks = false;
datepickerPopupConfig.showButtonBar = false;
});
testApp.controller('DateRangeCtrl', function($scope) {
$scope.items = [
{ID: "1", dateAdded: "01-04-2013"},
{ID: "2", dateAdded: "12-01-2013"},
{ID: "3", dateAdded: "12-31-2013"},
{ID: "4", dateAdded: "01-12-2014"},
{ID: "5", dateAdded: "03-04-2014"}
];
$scope.parseDate = function(input){
var parts = input.split('-');
var newParts = new Date(parts[2], parts[0]-1, parts[1]); // Note: months are 0-based
return newParts;
}
$scope.open1 = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened1 = true;
};
$scope.maxFromDate = new Date();
$scope.maxToDate = new Date();
$scope.setMinToDate = function (){
$scope.dt2 = null;
$scope.minToDate = $scope.dt1;
};
$scope.open2 = function($event) {
$event.preventDefault();
$event.stopPropagation();
$scope.opened2 = true;
};
});
How can i filter rows based on selected dates? For e.g. if i select "01/01/2014" in the "From" datePicker then i should be able to see all the rows whose "Date Added" column has value more than "January 1, 2014". The output will be rows with ID: 4 and 5.
It should behave the literal equivalent way when the "To" datePicker is selected
Please help me out. i'm stuck!
Update:
HTML
<tr ng-repeat="item in items | filter:dateFilter ">
JS
$scope.dateFilter = function (item) {
return (item.dateAdded < $scope.dt2);
};
Am i doing anything wrong? It still doesn't work....
By some hit n trial method, i eventually got it right. The problem was the "item.dateAdded" string had to be converted to Date object. Solution is adding the following piece of code in the js file:
$scope.filterDateAdded = function (){
if($scope.dt1 != null)
{
$scope.dateFilter = function (item) {
return ($scope.parseDate(item.dateAdded) >= $scope.dt1 && $scope.parseDate(item.dateAdded) <= $scope.dt2);
};
}
};
Cheers!
Change your code like this
<input type="text" datepicker-popup="MM-dd-yyyy" ng-model="dt2" is-open="opened2" min="minToDate" max="maxToDate" ng-model="search" ng-change="filterDateAdded()"/>
<tr ng-repeat="item in items | filter:dateFilter">
$scope.filterDateAdded=function()
{
$scope.dateFilter = function () {
var result=[];
for(var i in $scope.item)
{ if($scope.item[i].dateAdded >$scope.search)
{
result.push($scope.item[i]);
}
}
return result;
};
}

Resources