How do I delete an element returned from the each enumerator? - prototypejs

I have an array containing objects. Each object has an id field. I want to implement a function that deletes an object by specifying the id. I use .each from prototypejs on the array to step through the objects and check the id. If it matches, how do I actually delete it? I've tried setting the object returned from .each to null, but using FireBug I see that the object is still the same in the array.
EDIT: the objects in the array may in turn contain arrays with objects that may need to be deleted. My function is fine for finding the object to be removed, and I use splice to remove it (using a counter). It seems to me that .each (and the other enumerators like .reject) returns a copy of the object. If I set the object to null then upon inspection the object is still in the array. How would I return a reference of the object that when set to null would actually operate on the object in the array, and not a copy?
Here is the function, the deleteChild function works on the same principal:
function removeControl(controlName) {
var counter = 0;
cont.each(function (existingControl) {
if (existingControl.id == controlName) {
existingControl.destroy();
cont.splice(counter, 1);
}
else { // not found, check control's children
existingControl.deleteChild(controlName);
}
counter++;
}, this);
}

Only use .each when you want to do something to every object. Semantically speaking, you should be using Enumerable.reject in this situation. Think how much easier it will be to understand when you have to fix it in years' time.
function deleteById(objects, id) {
return objects.reject(function(obj) {
return obj.id == id;
}).each(function(obj) {
obj.deleteChild(id);
});
}

Related

RxJs: How to return an Observable<T> from an Observable<T[]>?

I'm calling a web service that returns a List. I want to return one item from that List, in a method. Essentially, when some function requests an instance of CollectorIssueBase, I want to retrieve ALL of them, cache them and return the one requested. But I can't figure out how to do it.
Here's my code:
public getByID(collectorID: string, id: string): Observable<CollectorIssueBase> {
return this.getAllMinimized(collectorID).pipe(
single(items => {
var item = items.find(i => i.ID == id);
return item;
})
);
}
The compiler keeps complaining that "Argument of type 'CollectorIssueValue[]' is not assignable to parameter of type 'CollectorIssueValue' which tells me right off the bat that I'm still returning an Array.
The value returned to the subscribing function is, indeed, an Array.
So what am I doing wrong? "single" seemed like the proper operator to use...am I using it wrong?
single callback takes CollectorIssueValue[] form each observable tick. If you want to change CollectorIssueValue[] to CollectorIssueValue i suggest use filter and map. Filter will filter empty arrays, and map will transform not empty array of CollectorIssueValue into CollectorIssueValue.
e.g.:
.pipe(
filter(arr => arr.length > 0),
map(arr => arr.find(...),

How to store parameters for action to be used again later

I have a list view that can be sorted, searched and filtered. From that list view the user can edit items in multiple steps. Finally after editing and reviewing the changes the user goes back to the list. Now I want the list to use the same sorting, search term and filters that the user set before and show the correct results.
How can multiple paramters (sorting, search, filter) be stored and reused when showing the list action?
Possible unsatisfactory ways that I thought of:
pass through all the needed parameters. Does work hardly if there are multiple actions involved between the two list action calls
save the parameters in the session object. This seems to require a lot of code to handle multiple parameters (check if parameter was passed to action, store new value, if parameter was not passed, get old parameter from session, handle empty string parameters):
Long longParameter
if(params.containsKey('longParameter')) {
longParameter = params.getLong('longParameter')
session.setAttribute('longParameter', longParameter)
} else {
longParameter = session.getAttribute('longParameter') as Long
params['longParameter'] = longParameter
}
If you want to make it more generic you could use an Interceptor instead.
This could perhaps be generalized like this:
class SessionParamInterceptor {
SessionParamInterceptor() {
matchAll() // You could match only controllers that are relevant.
}
static final List<String> sessionParams = ['myParam','otherParam','coolParam']
boolean before() {
sessionParams.each {
// If the request contains param, then set it in session
if (params.containsKey(it)) {
session[it] = params[it]
} else {
// Else, get the value from session (it will be null, if not present)
params[it] = session[it]
}
}
true
}
}
The static sessionParams holds the parameters you want to store/retrieve from session.
If the params contains an element from the list, it is stored in session under the same name. If not, it is taken from session (given that it exists).
In your controller, you can now just access params.getLong('theParam') like you always would. You could also use Grails parameter conversion:
def myAction(Long theParam) {
}
Lots of LOC saved.
I use the session as well. Here is a sample that you may adapt to your needs:
def list() {
if (request.method == 'GET' && !request.queryString) {
if (session[controllerName]) {
// Recall params from memory
params.putAll(session[controllerName])
}
} else {
// Save params to memory and redirect to get clean URL
session[controllerName] = extractParams(params)
redirect(action: actionName)
return
}
// Do your actions here...
}
def extractParams(params) {
def ret = [:]
params.each { entry ->
if (entry.key.startsWith("filter_") || entry.key == "max" || entry.key == "offset" || entry.key == "sort" || entry.key == "order") {
ret[entry.key] = entry.value
}
}
return ret
}
Using session is your best bet. Just save the preference when preferred. I mean, when user sorts, or filter, just save that information in the session, for that particular <controller>.<action>, before returning the page. Next time, check the session, if it has anything related to that <controller>.<action>, apply those; otherwise render the default page.
You might like to use some Interceptor for this, as suggested by sbglasius, here.
I hope you're getting my point.

Regarding the Efficiency of the LINQ Any() Method

Is there any performance difference between these two approaches?
// First approach, iterating until a match
public bool Find(IEnumerable<Object> allObjects, Object testObj)
{
foreach (Object obj in allObjects)
{
if (obj.Equals(testObj))
{ return true; }
}
return false;
}
// Second approach, using LINQ and Any()
public bool Find(IEnumerable<Object> allObjects, Object testObj)
{
var query = from Object obj in allObjects where obj.Equals(testObj) select obj;
return query.Any();
}
My question is whether the LINQ version compares testObj to all objects in the collection and then the Any() method checks if the resulting collection is empty. This would be generally less efficient than the first case where the iteration stops after the first match.
No, the performance should be equivalent - Any() will stop iterat​ing over the source enumeration after the first match.
Also you could do this more concise (and easier to read and understand, but that's a matter of opinion) using method syntax:
return allObjects.Any(obj => obj.Equals(testObj));

How can I create temporary records of Linq-To-Sql types without causing duplicate key problems?

I have code that generates records based on my DataGridView. These records are temporary because some of them already exist in the database.
Crop_Variety v = new Crop_Variety();
v.Type_ID = currentCropType.Type_ID;
v.Variety_ID = r.Cells[0].Value.ToString();
v.Description = r.Cells[1].Value.ToString();
v.Crop = currentCrop;
v.Crop_ID = currentCrop.Crop_ID;
Unfortunately in this little bit of code, because I say that v.Crop = currentCrop,
now currentCrop.Crop_Varieties includes this temporary record. And when I go to insert the records of this grid that are new, they have a reference to the same Crop record, and therefore these temporary records that do already exist in the database show up twice causing duplicate key errors when I submit.
I have a whole system for detecting what records need to be added and what need to be deleted based on what the user has done, but its getting gummed up by this relentless tracking of references.
Is there a way I can stop Linq-To-Sql from automatically adding these temporary records to its table collections?
I would suggest revisiting the code that populates DataGridView (grid) with records.
And then revisit the code that operates on items from a GridView, keeping in mind that you can grab bound item from a grid row using the following code:
public object GridSelectedItem
{
get
{
try
{
if (_grid == null || _grid.SelectedCells.Count < 1) return null;
DataGridViewCell cell = _grid.SelectedCells[0];
DataGridViewRow row = _grid.Rows[cell.RowIndex];
if (row.DataBoundItem == null) return null;
return row.DataBoundItem;
}
catch { }
return null;
}
}
It is also hard to understand the nature of Crop_Variety code that you have posted. As the Crop_Variety seems to be a subclass of Crop. This leads to problems when the Crop is not yet bound to database and potentially lead to problems when you're adding Crop_Variety to the context.
For this type of Form application I normally have List _dataList inside form class, then the main grid is bound to that list, through ObjectBindingList or another way. That way _dataList holds all data that needs to be persisted when needed (user clicked save).
When you assign an entity object reference you are creating a link between the two objects. Here you are doing that:
v.Crop = currentCrop;
There is only one way to avoid this: Modify the generated code or generate/write your own. I would never do this.
I think you will be better off by writing a custom DTO class instead of reusing the generated entities. I have done both approaches and I like the latter one far better.
Edit: Here is some sample generated code:
[global::System.Data.Linq.Mapping.AssociationAttribute(Name="RssFeed_RssFeedItem", Storage="_RssFeed", ThisKey="RssFeedID", OtherKey="ID", IsForeignKey=true, DeleteOnNull=true, DeleteRule="CASCADE")]
public RssFeed RssFeed
{
get
{
return this._RssFeed.Entity;
}
set
{
RssFeed previousValue = this._RssFeed.Entity;
if (((previousValue != value)
|| (this._RssFeed.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._RssFeed.Entity = null;
previousValue.RssFeedItems.Remove(this);
}
this._RssFeed.Entity = value;
if ((value != null))
{
value.RssFeedItems.Add(this);
this._RssFeedID = value.ID;
}
else
{
this._RssFeedID = default(int);
}
this.SendPropertyChanged("RssFeed");
}
}
}
As you can see the generated code is establishing the link by saying "value.RssFeedItems.Add(this);".
In case you have many entities for wich you would need many DTOs you could code-generate the DTO classes by using reflection.

Linq GroupBy how to return a collection of objects that are grouped into another list?

I'm having a difficult time trying to return a collection of objects after I use Linq to do a GroupBy on the collection.
The specifics are, I have a collection of CurrentSegmentGroupDetail objects being returned when I call a view from EF 4.1. Using a Lambda expression, I group the CurrentSegmentGroupDetail object by a SegmentGroup property. The result I get is a list of SegmetGroups that contain CurrentSegmentGroupDetail objects. The problem I'm having is trying to return the grouped result set back to a type of List.
Here is the code I have so far:
public List<CurrentSegmentGroupDetail> GetSegmentGroupsForReconciliation()
{
using (var context = new PricingContext())
{
var segmentGroups =
context.CurrentSegmentGroupDetails.GroupBy(s => s.SegmentGroup).Select(y => y);
return segmentGroups;
}
}
Here is the exception I'm getting when I try and pass the result set into my List object:
"Cannot implicitly convert type 'System.Linq.IQueryable>' to 'System.Collections.Generic.List'.
I would greatly appreciate any help on this.
ToList()
return segmentGroups.ToList();

Resources