angularjs ng-repeater dynamically delete data - angularjs

I have a situation where users added sample data as shown in figure. How can I add Delete button which deletes particular sample ONLY. From figure , I want 'Delete Sample 1" to delete Sample 1 records only.
Thanks
Code triggered when Add Sample button is clicked
$scope.addSample = function () {
$scope.partdetails = [
{
"sampleseq": 0,
"sampleid": 1,
"attribute": "Height",
"measureunit": "Centimeter",
"actualvalue": null,
"lowerspec": 1.23,
"upperspec": 3.23,
"notes": null
},
{
"sampleseq": 0,
"sampleid": 2,
"attribute": "Diameter",
"measureunit": "Inches",
"actualvalue": null,
"lowerspec": 1.23,
"upperspec": 3.23,
"notes": null
}
];
$scope.partdetails[0].sampleseq = $scope.sampleCount;
$scope.partdetails[1].sampleseq = $scope.sampleCount;
$scope.partdetailsList.push($scope.partdetails[0]);
$scope.partdetailsList.push($scope.partdetails[1]);
$scope.sampleCount += 1;
}

This link has the solution just modify the list accordinlgy
https://coderwall.com/p/fnp2oq/use-ng-repeat-on-tbody-to-create-summary-rows-for-nested-data

You can use Array.prototype.filter to get a new data record without the items that fail a predicate function
Lets say your delete button calls a function called deleteSample and passes it a sample id:
HTML:
... ng-repeat="row in records" ...
<button ng-click="deleteSample(row.sampleid)">Delete sample</button>
Controller:
$scope.deleteSample = function(sampleId) {
$scope.records = $scope.records.filter((row)=> {
return !angular.equals(sampleId, row.sampleid)
});
}
Of course that doesn't solve the issue that you would probably need to remove the rows in your db too.

Related

How can i always call a function on Master - Detail Kendo grid row expansion?

I am using Master detail in Kendo Grid in AngularJS.
Here is the setup of the code:
In cshtml is:
<script type="text/x-kendo-template" id="template">
<div>
<div class="orders"></div>
</div>
</script>
In the AngularJS controller is
The MasterRowId is the id of the Column in the Master row. So the Master grid is a grid with
columns Id and name
$scope.getorders = function (masterRowId)
{
myservice.getorders(masterRowId)
.then(function (result) {
for (var j = 0; j < result.data.length; j++)
$scope.ordergroupdata.push(result.data[j]);
});
}
In the master grid definition i have
......
detailTemplate: kendo.template($("#template").html()),
detailInit: $scope.detailInit,
The definition of $scope.detailInit is
$scope.detailInit = function (e)
{
$scope.MasterRowId = e.data.Id;
$scope.getorders ($scope.MasterRowId);
var orderdata = $scope.ordergroupdata;
var orderdatasource = new kendo.data.DataSource({
transport: {
read: function (e) {
e.success(orderdata);
},
update: function (e) {
e.success();
},
create: function (e) {
var item = e.orderdata;
item.Id = orderdata.length + 1;
e.success(item);
}
},
schema: {
model: {
id: "Id",
fields: {
OrderId: { type: 'string'},
}
}
},
});
e.detailRow.find(".orders").kendoGrid({
dataSource: orderdatasource,
columns: [
{ field: "OrderId", title: "OrderId" },
]
});
}
The issue is that if i click on the first row , i can retrieve the data according to the MasterRowId from my MVC action method. So If i click on the first row and the MasterRowId is for example 10 , then i get an OrderId of "1234" .
I can click on the second row with MasterRowID of 15 and it will retrieve the OrderId of "8231", BUT if i go back to the first row the data (OrderId) in the details grid is actually the data from the second row, so its "8321" NOT "1234".
How can i always call the $scope.detailInit so that i can go back to the MVC Action method and always retrieve the correct data for that particular row with that MasterRowId ?
Once i expand the row and move on to another row , the detailsInit doesnt get called any more for that row ?
detailInit is only called on first expand, but you can use detailExpand that is called every time you expand the detail table.
Offical example:
<script>
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: [
{ name: "Jane Doe", age: 30 },
{ name: "John Doe", age: 33 }
],
detailTemplate: "<div>Name: #: name #</div><div>Age: #: age #</div>",
detailExpand: function(e) {
console.log(e.masterRow, e.detailRow);
}
});
</script>
Docs: detailExpand
Official example: detailExpand example

Group objects by field, then group by a conditional field

I have a list of objects that I'm using an ng-repeat to display.
I need to be be able to group these objects by a field, such as an departmentID.
I then need to be able to loop through each department, and then by the 2nd field, which will either be preliminary or final. If there is a final record for a given department, the preliminary record should be hidden. If there is no final for a given department, show the preliminary.
Ex.
Department 1
Preliminary - not visible
Department 1
Final - visible
Department 2
Final - visible
Department 3
Preliminary - not visible
Department 3
Final - visible
Department 4
Preliminary - visible
Data Sample
var data = [
{ departmentID: 1, status: 'preliminary' },
{ departmentID: 1, status: 'final' },
{ departmentID: 2, status: 'final' },
{ departmentID: 3, status: 'preliminary' },
{ departmentID: 3, status: 'final' },
{ departmentID: 4, status: 'preliminary' },
];
Current code below
if (item.result_status !== "preliminary") {
return item;
}
else if (item.result_status === "final") {
return item;
}
else {
return false;
}
<div ng-repeat="(key, value) in Data | groupBy: 'department_ID'">
<div ng-repeat="v in value | filter:prelimFilter(value)">
<a ng-click="showPopUp(key)">{{Some Other Field}} </a>
</div>
</div>
<!-- begin snippet: js hide: false console: true babel: false -->
You are close! Your first half of the code is correct where you group the object based on departmentID using groupBy filter. The issue is with your custom filter. You have created a filter function instead of custom filter and the issue is filter function does not have access to entire array. It has access only to individual elements. This blog explains clearly the different types of filter that can be created in angularjs.
You can create a custom filter which has access to the array and you can return the filtered array based on status
.filter('myFilter', function () {
return function(inputArr) {
var outputArr = [];
outputArr = inputArr.filter(function(obj){return obj.status === "final"});
outputArr = outputArr.filter(function(e){return e}); //To remove empty elements
if(outputArr.length === 0){
outputArr = inputArr; //inputArr does not have obj with status 'final'
}
return outputArr;
};
});
Working jsfiddle here. Good luck!
NOTE: groupBy filter is not part of angular.js You have to include angular.filter module.

AngularJS filter already selected option from dynamic field

I have a form where you can add x number of fields. Each field contains option select. I want to filter out the already chosen option when this option is already chosen in one or multiples field before. Each field has a remove button and the form has 1 add button.
How can I filter out the dynamic fields?
Any help,guidance is most welcome.Thanks in advance. :)
This is how my HTML looks like:
<div data-ng-repeat="choice in choices">
<select data-ng-model="choice.option"
data-ng-options="item as item.Value for item in options">
</select>
<button data-ng-click="removeChoice(choice)">Remove choice</button>
<div>
<button data-ng-show="choices.length <= 4" data-ng-click="addNewChoice()">Add Choice</button>
</div>
</div>
And my controller:
$scope.options = [
{
"Key": "0",
"Value": "Select an option"
},
{
"Key": "Option1",
"Value": "Option1"
},
{
"Key": "Option2",
"Value": "Option2"
},
{
"Key": "Option3",
"Value": "Option3"
},
{
"Key": "Option4",
"Value": "Option4"
},
{
"Key": "Option5",
"Value": "Option5"
}
];
$scope.choices = [{ id: '1' }];
$scope.addNewChoice = function () {
var newItemNo = $scope.choices.length + 1;
$scope.choices.push({ id: newItemNo, option: $scope.option, value: $scope.value });
};
$scope.removeChoice = function () {
var index = $scope.choices.indexOf(choice);
$scope.choices.splice(index, 1);
};
ok
i can give simple recommendation which will be this.
1: add variable $scope.selectedOptions = [];
this will contain list of already selected options from all select elements .
2: create function $scope.AddSelectedOption(item);
this will add the selected object when we change option from any select element because we are going to use for all selects ng-change= "AddSelectedOption(item);"
3: add checkIfSelected(item); this will check if given object value is already selected or not ..
will user in
hope you understand what it will do just check like this
$scope.checkIfSelected = function (item) {
$scope.selectedFound = $scope.selectedOptions.filter(function
(option) {
if(option.value == item.value)
{
return day;
}
});
if($scope.selectedFound.length == 0 ) { return false; } else {
return true; }
}
This will return true if give item found in the options.
if not out.. you can invite me to help again .
This is possible. I'm explaining a basic version of this requirement. See the working example here http://plnkr.co/edit/S9yZpjhY55lXsuifnUAc?p=preview
What wer are doing is maintaining another options which is the copy of the original options. Copying the options will make it to not reference existing options since objects are pass by reference in Javascript.
The main logic is in this function, which modify the options on selection:
$scope.optionSelected = function(choice) {
$scope.availableOptions = $scope.availableOptions || angular.copy($scope.options);
if (choice.option) {
var index = -1;
// See if available options has that key
angular.forEach($scope.availableOptions, function(item, i) {
if (item.Key === choice.option.Key) {
index = i;
}
});
if (index > -1) {
// And then remove it
$scope.availableOptions.splice(index, 1);
}
}
};

Angular.js - How to make limitTo dynamic and persistant inside a nested ng-repeat with real time socket.io data updates

So I have an app that is updating data in real time using socket.io and displaying it with Angular JS.
I have it displaying data (comments) in multiple ng-repeats which are using ‘track by’ to ensure that duplicates are ignored when the latest data is brought in. I’m also using LimitTo to only show a certain amount of comments at a time, LimitTo is dynamic and is increased when the user clicks a button.
The HTML
<div ng-controller="CommentsController" >
<!-- Comment Repeater Starts Here -->
<div ng-repeat="comment in comments | limitTo: limit track by comment.id" >
{{ comment.comment }}
<!-- Nested Reply Comments Start Here -->
<div ng-repeat="reply in comment.replies | limitTo: comment.limit track by reply.id" >
<div class="comment-text" >
{{ reply.comment }}
</div>
</div>
<a href="#" ng-click="increaseReplyLimit(comment, comment.limit)" ng-show="hasMoreComments(comment.replies, comment.limit)" >View More Replies</a>
</div>
<a href="#" ng-click="increaseLimit(limit)" ng-show="hasMoreComments(comments,limit)" >View More Comments</a>
It works perfectly fine for my first ng-repeat, because I assign LimitTo to a variable on the scope, which is unaffected when I bring in new data through Socket.io. For my nested ng-repeat, though, I am using comment.limit as the variable for the LimitTo and this gets overwritten every single time I bring in the new data through socket.io.(the new data has a default for comment.limit - i tried leaving this blank before but then nothing shows).
The Angular
app.controller('CommentsController', function ($scope,socket,$http,$location) {
// fetching the latest comments from the API location
$http.get( $url + 'comments').success(function(comments) {
if (comments) {
$scope.comments = comments;
}
});
// updating comments via socket.io
socket.on('comment.update', function (data) {
$scope.comments = JSON.parse(data);
});
$scope.limit = 2;
$scope.hasMoreComments = function(comments, limit) {
if (typeof comments != "undefined" && comments != "false") {
var $commentLength = comments.length;
if ($commentLength > limit) {
return true;
}
return false;
}
return false;
}
$scope.increaseLimit = function(limit) {
$scope.limit = $scope.limit + 2;
}
$scope.increaseReplyLimit = function(comment, limit) {
comment.limit = parseInt(limit) + 2;
}
});
How can I prevent the current limit for each nested repeat from getting overwritten when I bring in new data from socket.io?
I already tried doing a deep merge on both the old and new data (with the idea of updating the nested limit in the new data to reflect the current nested limit). However, when i did that, Angular completely ignored the new limit and no longer enforced any limit for nested comments.
Structure of the data being brought in
[
{
"topics": [
{
"id": 75,
"topic": "test",
"approved": 1,
"created_at": "-0001-11-30 00:00:00",
"updated_at": "-0001-11-30 00:00:00",
"slug": "test",
"blurb": null
}
],
"id": 849,
"user_id": 80,
"news_id": 9,
"context": "Test News Article 1",
"comment": "<p>test comment 4</p>",
"origin": "Test",
"origin_url": "http://localhost:8000/news/test-news-article-1",
"author": "omurphy27",
"author_url": null,
"votes": 0,
"created_at": "2015-06-08 22:36:53",
"updated_at": "2015-06-08 22:36:53",
"approved": 1,
"slug": "test-comment-116",
"original": 1,
"parent_id": null,
"username": "omurphy27",
"limit": 2,
"voted": false
}
]
Been banging my head against the wall for awhile with this one and any help is much appreciated.
I ended up creating a separate array for my nested reply limits and attaching it to the scope (rather than having these limits in the data object that was being brought in and updated in realtime by socket.io )
See my updated angular code below
app.controller('CommentsController', function ($scope,socket,$http,$location) {
// fetching the latest comments from the API location
$http.get( $url + 'comments').success(function(comments) {
if (comments) {
$scope.comments = comments;
}
// populate my separate array for reply limits
$scope.populateLimits(comments.length, 4);
});
$scope.populateLimits = function(limitLength, limit) {
var limits = [];
for (var i = limitLength - 1; i >= 0; i--) {
limits[i] = limit;
};
$scope.limits = limits;
}
// updating comments via socket.io
socket.on('comment.update', function (data) {
if (data.length > $scope.comments.length) {
var difference = data.length - $scope.comments.length;
// increment the limits array by however
// many new comments are pulled in by socket.io
$scope.incrementLimits(difference);
}
$scope.comments = JSON.parse(data);
});
$scope.incrementLimits = function(difference) {
var newLimits = $scope.limits;
for (var i = 0; i < difference; i++) {
newLimits.unshift(2);
};
$scope.limits = newLimits;
}
$scope.limit = 2;
$scope.hasMoreComments = function(comments, limit) {
if (typeof comments != "undefined" && comments != "false") {
var $commentLength = comments.length;
if ($commentLength > limit) {
return true;
}
return false;
}
return false;
}
$scope.increaseLimit = function(limit) {
$scope.limit = $scope.limit + 2;
}
$scope.increaseReplyLimit = function(limit,index) {
$scope.limits[index] = parseInt(limit) + 2;
}
});
I populate this separate limits array based on how many 'parent' comments I have and then I increment it by however many new comments are brought in. Right now I'm just showing comments based in order, with the newest shown first, so I don't have to track which 'limits' belong to which comment; I can simply add new ones to the beginning of the array.
As for accessing the $scope.limits array in my nested ng-repeat and using it as the LimitTo variable, I do so using the following variable: limits[$index].
See my updated markup below:
<div ng-controller="CommentsController" >
<!-- Comment Repeater Starts Here -->
<div ng-repeat="comment in comments | limitTo: limit track by comment.id" >
{{ comment.comment }}
<!-- Nested Reply Comments Start Here -->
<div ng-repeat="reply in comment.replies | limitTo: limits[$index] track by reply.id" >
<div class="comment-text" >
{{ reply.comment }}
</div>
</div>
<a href="#" ng-click="increaseReplyLimit(limits[$index], $index)" ng-show="hasMoreComments(comment.replies, limits[$index])" >View More Replies</a>
</div>
<a href="#" ng-click="increaseLimit(limit)" ng-show="hasMoreComments(comments,limit)" >View More Comments</a>
</div>
The above fixes the issue I was having where the dynamic variable I was using for the limitTo for my nested ng-repeat kept getting overwritten. I do need to have the $scope.limits sync up better with my data, but I hope this helps anyone else who was encountering the same issue.
Cheers

Using object property in select

I currently have the following select:
<select ng-model="current_event"
ng-options="event.event_id for event in current_level.events.event"
ng-change="currentEventChanged()">
</select>
current_level.events.event is an array of objects which looks like this:
[
{
"event_id": 0,
"event_type": {
"collision": {
"object_id1": 0,
"object_id2": 1,
"allow_overlap": "no"
}
}
},
{
"event_id": 1,
"event_type": {
"player_input": {
"object_id": 0,
"level_id": 0,
"allow_overlap": "no"
}
}
}
]
The select works perfectly, but the text for each option is just the event_id, e.g. "0" or "1". I want the text for an item to actually be the event_type (with underscores converted to spaces), e.g. "collision" or "player input". Is this possible in AngularJS?
You're using event.event_id, so there is nothing wrong in the behaviour of AngularJS. You should simply put the right label in the ng-options of <select> (see the documentation).
However, you need to call a function before in order to obtain the correct label, since what you want is pretty complex.
$scope.getLabel = function (eventType)
{
var firstKey = null;
angular.forEach(eventType, function (value, key)
{
if (firstKey === null)
{
firstKey = key;
}
});
return firstKey.replace('_', ' ', 'g');
};
<select
ng-model="current_event"
ng-options="event.event_id as getLabel(event.event_type) for event in current_level.events.event"
ng-change="currentEventChanged()"
>
</select>
jsFiddle

Resources