Binding search on NavigationList - binding

My search method is working only on the first node of my jsonmodel, do i need to make another filter ?
///View
<tnt:NavigationList id="navlist" items="{path:'cars>/Desc'}" >
<tnt:NavigationListItem id="navlistitem" text="{cars>TITLE}" expanded="true" items="{path:'cars>ITEMS',templateShareable:true}"
key="{cars>number}">
<tnt:NavigationListItem id="navListItemSecond" text="{cars>TITLE}" key="{cars>number}">
</tnt:NavigationListItem>
</tnt:NavigationListItem>
</tnt:NavigationList>
//Controller (The search method)
onLiveSearch:function(evt) {
var filterString = evt.getParameter('newValue');
var filters = [];
var tree = this.getView().byId('navlist');
var binding = tree.getBinding('items');
if ( filterString && filterString.length > 0 ) {
var filter1 = new sap.ui.model.Filter( 'TITLE', sap.ui.model.FilterOperator.Contains,
filterString );
filters.push( filter1 );
}
binding.filter(filters);
},

Your question is somewhat similar to Filtering on Nested Aggregation Binding. Basically you have a two-level collection and (I guess) you want to be able to filter both levels (the items of the nav list and the child items of those items) with only one search.
What you have to do is actually filter both the top-level aggregations (the items aggregation of the NavigationList) and all the lower level aggregations (each of the items aggregations of the NavigationList's NavigationListItems).
Keep in mind that filtering on the navlistitem's items aggregation will not work, because this control is actually a template for the aggregation binding (it is cloned at runtime to obtain the items which are displayed). You will have to iterate through all the clones (= the items of the NavigationList) and apply the filter for each of them in order to achieve what you want.

Related

BeanItemContainer unique property values

I am using BeanItemContainer for my Grid. I want to get a unique list of one of the properties. For instance, let's say my beans are as follows:
class Fun {
String game;
String rules;
String winner;
}
This would display as 3 columns in my Grid. I want to get a list of all the unique values for the game property. How would I do this? I have the same property id in multiple different bean classes, so it would be nice to get the values directly from the BeanItemContainer. I am trying to avoid building this unique list before loading the data into the Grid, since doing it that way would require me to handle it on a case by case basis.
My ultimate goal is to create a dropdown in a filter based on those unique values.
There isn't any helper for directly doing what you ask for. Instead, you'd have to do it "manually" by iterating through all items and collecting the property values to a Set which would then at the end contain all unique values.
Alternatively, if the data originates from a database, then you could maybe retrieve the unique values from there by using e.g. the DISTINCT keyword in SQL.
In case anyone is curious, this is how I applied Leif's suggestion. When they enter the dropdown, I cycle through all the item ids for the property id of the column I care about, and then fill values based on that property id. Since the same Grid can be loaded with new data, I also have to "clear" this list of item ids.
filterField.addFocusListener(focus->{
if(!(filterField.getItemIds() instanceof Collection) ||
filterField.getItemIds().isEmpty())
{
BeanItemContainer<T> container = getGridContainer();
if( container instanceof BeanItemContainer && getFilterPropertyId() instanceof Object )
{
List<T> itemIds = container.getItemIds();
Set<String> distinctValues = new HashSet<String>();
for(T itemId : itemIds)
{
Property<?> prop = container.getContainerProperty(itemId, getFilterPropertyId());
String value = null;
if( prop.getValue() instanceof String )
{
value = (String) prop.getValue();
}
if(value instanceof String && !value.trim().isEmpty())
distinctValues.add(value);
}
filterField.addItems(distinctValues);
}
}
});
Minor point: the filterField variable is using the ComboBoxMultiselect add-on for Vaadin 7. Hopefully, when I finally have time to convert to Vaadin 14+, I can do something similar there.

List return Last item only mvc 4

below is my Action Method.It return Last item of list only. but I want list of Items in AList.
public ActionResult Ataxi(){
List<sub_employee> AList = new List<sub_employee>();
var alist = IM.getAvailableList().ToList();
foreach(var item in alist)
{
AList = db.sub_employee.Where(s => s.SE_ID == item).ToList();
}
return View(AList);
}
how do I get All elements in Alist. Can Somebody help me to solve this problem. thank you
I think you want something like this:
public ActionResult Ataxi(){
var list1 = IM.getAvailableList().ToList();
var list2 = db.sub_employee
.Where(x => list1.Contains(x.Id))
.ToList();
return View(list2);
}
In your example you keep overwriting the value of the list. You also check Where for each item of your original list against db.sub_employee, which is hard to read and not very efficient. You really only need to use Where once to filter the value whose key is not already in the list. Note that using Contains inside Where is horribly inefficient, but its simple to write and doesn't require creating new LINQ operators.
Also, on a style note, I would avoid starting local variable names with capital letters (Alist), and especially avoid local variables that only differ by capitalization (Alist vs alist). Conversely, it is standard to name types and properties starting with capital letters (sub_employee).

How to index sub-content in Sitecore with Lucene?

I'm using Sitecore 7.2 with MVC and a component approach to page building. This means that pages are largely empty and the content comes from the various renderings placed on the page. However, I would like the search results to return the main pages, not the individual content pieces.
Here is the basic code I have so far:
public IEnumerable<Item> GetItemsByKeywords(string[] keywords)
{
var index = ContentSearchManager.GetIndex("sitecore_master_index");
var allowedTemplates = new List<ID>();
IEnumerable<Item> items;
// Only Page templates should be returned
allowedTemplates.Add(new Sitecore.Data.ID("{842FAE42-802A-41F5-96DA-82FD038A9EB0}"));
using (var context = index.CreateSearchContext(SearchSecurityOptions.EnableSecurityCheck))
{
var keywordsPredicate = PredicateBuilder.True<SearchResultItem>();
var templatePredicate = PredicateBuilder.True<SearchResultItem>();
SearchResults<SearchResultItem> results;
// Only return results from allowed templates
templatePredicate = allowedTemplates.Aggregate(templatePredicate, (current, t) => current.Or(p => p.TemplateId == t));
// Add keywords to predicate
foreach (string keyword in keywords)
{
keywordsPredicate = keywordsPredicate.And(p => p.Content.Contains(keyword));
}
results = context.GetQueryable<SearchResultItem>().Where(keywordsPredicate).Filter(templatePredicate).GetResults();
items = results.Hits.Select(hit => hit.Document.GetItem());
}
return items;
}
You could create a computed field in the index which looks at the renderings on the page and resolves each rendering's data source item. Once you have each of those items you can index their fields and concatenate all of this data together.
One option is to do this with the native "content" computed field which is natively what full text search uses.
An alternative solution is to make an HttpRequest back to your published site and essentially scrape the HTML. This ensures that all renderings are included in the index.
You probably will not want to index common parts, like the Menu and Footer, so make use of HTMLAgilityPack or FizzlerEx to only return the contents of a particular parent container. You could get more clever to remove inner containers is you needed to. Just remember to strip out the html tags as well :)
using HtmlAgilityPack;
using Fizzler.Systems.HtmlAgilityPack;
//get the page
var web = new HtmlWeb();
var document = web.Load("http://localsite/url-to-page");
var page = document.DocumentNode;
var content = page.QuerySelector("div.main-content");

LINQ query with omitted user input

so I have a form with several fields which are criteria for searching in a database.
I want to formulate a query using LINQ like so:
var Coll = (from obj in table where value1 = criteria1 && value2 = criteria2...)
and so on.
My problem is, I don't want to write it using If statements to check if every field has been filled in, nor do I want to make separate methods for the various search cases (criteria 1 and criteria 5 input; criteria 2 and criteria 3 input ... etc.)
So my question is: How can I achieve this without writing an excessive amount of code? If I just write in the query with comparison, will it screw up the return values if the user inputs only SOME values?
Thanks for your help.
Yes, it will screw up.
I would go with the ifs, I don't see what's wrong with them:
var query = table;
if(criteria1 != null)
query = query.Where(x => x.Value1 == criteria1);
if(criteria2 != null)
query = query.Where(x => x.Value2 == criteria2);
If you have a lot of criteria you could use expressions, a dictionary and a loop to cut down on the repetitive code.
In an ASP.NET MVC app, chances are your user input is coming from a form which is being POSTed to your server. In that case, you can make use of strongly-typed views, using a viewmodel with [Required] on the criteria that MUST be provided. Then you wrap your method in if (ModelState.IsValid) { ... } and you've excluded all the cases where the user hasn't given you something they need.
Beyond that, if you can collect your criteria into a list, you can filter it. So, you could do something like this:
filterBy = userValues.Where(v => v != null);
var Coll = (from obj in table where filterBy.Contains(value1) select obj);
You can make this more complex by having a Dictionary (or Lookup for non-unique keys) that contains a user-entered value along with some label (an enum, perhaps) that tells you which field they're filtering by, and then you can group them by that label to separate out the filters for each field, and then filter as above. You could even have a custom SearchFilter object that contains other info, so you can have filters with AND, NOT and OR conditions...
Failing that, you can remember that until you trigger evaluation of an IQueryable, it doesn't hit the database, so you can just do this:
var Coll = (from obj in table where value1 == requiredCriteria select obj);
if(criteria1 != null)
{
query = query.Where(x => x.Value1 == criteria1);
}
//etc...
if(criteria5 != null)
{
query = query.Where(x => x.Value5 == criteria5);
}
return query.ToList();
That first line applies any criteria that MUST be there; if there aren't any mandatory ones then it could just be var Coll = table;.
That will add any criteria that are provided will be applied, any that aren't will be ignored, you catch all the possible combinations, and only one query is made at the end when you .ToList() it.
As I understand of your question you want to centralize multiple if for the sake of readability; if I were right the following would be one of some possible solutions
Func<object, object, bool> CheckValueWithAnd = (x, y) => x == null ? true : x==y;
var query = from obj in table
where CheckValue(obj.value1, criteria1) &&
CheckValue(obj.value2, criteria2) &&
...
select obj;
It ls flexible because in different situations or scenarios you can change the function in the way that fulfill your expectation and you do not need to have multiple if.
If you want to use OR operand in your expression you need to have second function
Func<object, object, bool> CheckValueWithOr = (x, y) => x == null ? false : x==y;

iterate through array and compare to entity object

I'm trying to get the various items in a one to many relationship of database objects. So I have the entity framework create my locations object and one column in the table has a comma separated list of services available at a location. I use:
var data = pubDB.Locations.Include("Branch_Ameneties");
in the model to get the relationsihp between a the two tables. Then in the view I am trying to iterate through the features in an array and get the associated Branch Amenities:
#foreach (var Location in Model.LocationListings())
{
#if (Location.Features != null)
{
string[] featureset = Location.Features.Split(',');
foreach (var item in featureset)
{
var feature = Location.Branch_Ameneties.Amenity.Where(x => Location.Branch_Ameneties.FID = Convert.ToInt32(item);
#feature
}
}
And I can't seem to get the array to associate with the reference table of amentiites.
instead of using the where clause, try using:
var feature = Location.Branch_Ameneties.Amenity.Single(x => Location.Branch_Ameneties.FID == Convert.ToInt32(item));
Also, you had "..FID = Convert.ToInt32(item)" instead of "..FID == Convert..."

Resources