i am working with applying view criteria programaticlly, till now it was fine, but when i searched with "develop and unit test" it is showing 0 records even though my table having data. iam using like operator. could any one help on this .
i have one table, having option to filter by providing select combo box list of vales, for every column when i select any thing in lov in value change listener i am applying viewcriteria programatically on table vo.
note. every thing is programatic view object only there is no point of entity, or sql
Sample Code:
DCIteratorBinding bindIterator = ADFUtils.findIterator("Tri2EWS_ETKAPIData_VO1Iterator");//Table viewObject(programatic)
Tri2EWS_ETKAPIData_VOImpl voimpl = (Tri2EWS_ETKAPIData_VOImpl) bindIterator.getViewObject();
ViewCriteria viewCriteria = voimpl.createViewCriteria();
viewCriteria.setName("MyVc");
ViewCriteriaRow viewCriteriaRow = viewCriteria.createViewCriteriaRow();
viewCriteriaRow.setOperator("ViewAttr1", "LIKE");
viewCriteriaRow.setAttribute("ViewAttr1", "stack and OverFlow");
viewCriteria.add(viewCriteriaRow);
viewCriteria.setCriteriaMode(ViewCriteria.CRITERIA_MODE_CACHE);
voimpl.applyViewCriteria(viewCriteria, true);
voimpl.executeQuery();
voipmpl.getRowCount();//Getting 0 here (Actually i should get 1)
Turn on debug messages for ADF BC (jbo.debugoutput) so you can see the SQL that is being generated.
This will help you figure out if the query is correctly formatted.
I have a requirement in which I have an af:query panel which after querying populates an af:table.
Now based on the table rows when any 1 row is selected, the graphs below it should be populated based on some columns.
Now my problem is that on search when the table is populated for the first time, no row is selected.
I need the first row to be selected automatically. I have searched multiple solutions from the net forums but till now haven't found any working solution.
Please help me what code should I use to select a row programmatically. and also where should I put this code in the backing bean.
As you've correctly mentioned, at the first render of the table no row is selected. I've encountered this problem too, and i've dealt with it by calling a getting the first row of the corresponding VO on BeforePhase (i.e: on the page first rendering or refresh).
I understand that you intend to do so for the first searching.
The af:query component has a property called QueryListener. You can link it with a method inside a backing bean. The content should be like:
private QueryEvent qEvent = null;
public void queryListener(QueryEvent queryEvent) {
setQEvent(queryEvent);
JSFUtils.invokeMethodExpression("#{bindings.YourViewObjectNameViewCriteriaQuery.processQuery}", Object.class,
QueryEvent.class, getQEvent());
BindingContainer bindings = BindingContext.getCurrent().getCurrentBindingsEntry(); //Edited
DCBindingContainer bc = (DCBindingContainer)bindings;
DCIteratorBinding iterator = bc.findIteratorBinding("YourViewObject1Iterator");
Row r = iterator.getCurrentRow(); //Here you've got the very first row, and can operate with it
.....
}
public void setQEvent(QueryEvent qEvent) {
this.qEvent = qEvent;
}
public QueryEvent getQEvent() {
return qEvent;
}
With this, you should be able to get the first row when the query is executed (i.e: when the search is done).
After getting the first row, you can programmatically the graph process execution or whatever you do.
NOTE: invokeMethodExpression can be found inside JSFUtils, which is a starndard class with static methods which source code you can download here: JSFUtils.java
I've been searching for hours but I couldn't find an answer to my question: I've set up a ListGrid similar to the one shown here (Link). Right now I am using a XML-File as data source (default rows) just like in the example. It is also possible to add and delete rows to/from the grid.
Therefore I would like to store every user's data from the grid in a data store (Google Datastore). So I need to read all the rows of the current user as Strings. What would be a good way to do that? I already tried the following, but without success:
ListGrid componentsGrid = new ListGrid();
componentsGrid.setWidth(500);
componentsGrid.setHeight(224);
componentsGrid.setCellHeight(22);
componentsGrid.setDataSource(ComponentsXmlDS.getInstance());
componentsGrid.setAutoFetchData(true);
componentsGrid.setCanEdit(true);
componentsGrid.setModalEditing(true);
componentsGrid.setEditEvent(ListGridEditEvent.CLICK);
componentsGrid.setListEndEditAction(RowEndEditAction.NEXT);
componentsGrid.setAutoSaveEdits(false);
layout.addMember(componentsGrid);
//First try
componentsGrid.fetchData();
logger.log(Level.INFO, "Components: "+ componentsGrid.getResultSet().get(0).getAttribute("componentType"));
//Second try
logger.log(Level.INFO, "Components: "+ componentsGrid.getAllFields());
// Third try
logger.log(Level.INFO, "Components: "+ componentsGrid.getRecords());
Anyone having a hint? Help is greatly appreciated.
If I understand well your requirement you want to read all the rows of the grid and store their data in a db.
I think you can use:
getRecordList() which *Return the underlying data of this DataBoundComponent as a RecordList.
You will be able to iterate inside this list, extract the attribute value you want for every record and store these data in your db.
Or use the getRecords() method as you said and iterate in the array of ListGridRecord obtained.
To iterate through your RecordList you have to transform it to an array, for example with a lot of dummy objects and methods:
RecordList data = MyGrid.getRecordList();
for(Record record : data.toArray()){
MyDataObject obj = new MyDataObject()
obj.setId(record.getAttribute("thId"));
obj.setOne(record.getAttribute("anAttribute"));
obj.setTwo(record.getAttribute("anotherAttribute"));
obj.StoreToDb();
}
I'm trying to figure out how to populate a table from a JSON array. So far, I can populate my table cells perfectly fine by using the following code:
self.countries = [[NSArray alloc]initWithObjects:#"Argentina",#"China",#"Russia",nil];
Concerning the JSON, I can successfully retrieve one line of text at a time and display it in a label. My goal is to populate an entire table view from a JSON array. I tried using the following code, but it still won't populate my table. Obviously I'm doing something wrong, but I searched everywhere and still can't figure it out:
NSURL *url = [NSURL URLWithString:#"http://BlahBlahBlah.com/CountryList"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON)
{
NSLog(#"%#",[JSON objectForKey:#"COUNTRIES"]);
self.countries = [JSON objectForKey:#"COUNTRIES"];
}
failure:nil];
[operation start];
I am positive that the data is being retrieved, because the NSLog outputs the text perfectly fine. But when I try setting my array equal to the JSON array, nothing happens. I know the code is probably wrong, but I think I'm on the right track. Your help would be much appreciated.
EDIT:
This is the text in the JSON file I'm using:
{
"COUNTRIES": ["Argentina", "China", "Russia",]
}
-Miles
It seems that you need some basic JSON parsing. If you only target iOS 5.0 and above devices, then you should use NSJSONSerialization. If you need to support earlier iOS versions, then I really recommend the open source JSONKit framework.
Having recommended the above, I myself almost always use the Sensible TableView framework to fetch all data from my web service and automatically display it on a table view. Saves me a ton of manual labor and makes app maintenance a breeze, so it's probably something to consider too. Good luck!
I have some data that is fetched in another thread that updates a UICollectionView's header. However, I've not found an efficient way of reloading a supplementary view such as a header or footer.
I can call collectionView reloadSections:, but this reloads the entire section which is unnecessary. collectionView reloadItemsAtIndexPaths: only seems to target cells (not supplementary views). And calling setNeedsDisplay on the header itself doesn't appear to work either. Am I missing something?
You can also use (the lazy way)
collectionView.collectionViewLayout.invalidateLayout() // swift
[[_collectionView collectionViewLayout] invalidateLayout] // objc
More complex would be to provide a context
collectionView.collectionViewLayout.invalidateLayout(with: context) // swift
[[_collectionView collectionViewLayout] invalidateLayoutWithContext:context] // objc
You can then make a or configure the context yourself to inform about what should be updated see: UICollectionViewLayoutInvalidationContext
It has a function in there that you can override:
invalidateSupplementaryElements(ofKind:at:) // swift
Another option is (if you have already loaded the correct header/footer/supplementary view) and you only want to update the view with the new data than you can use one of the following functions to retrieve it:
supplementaryView(forElementKind:at:) // get specific one
visibleSupplementaryViews(ofKind:) // all visible ones
Same goes for visible cells with visibleCells. The advantage of just getting the view and not reloading a view entirely is that the cells retains it state. This is espically nice with table view cells when they use swipe to delete/edit/etc since that state is lost after reloading the cell.
If you feel fanatic you can of course also write some extensions to retrieve only cells/supplementary views of a given kind using generics
if let view = supplementaryView(forType: MySupplementaryView.self, at: indexPath) {
configure(view, at indexPath)
}
this assumes that you have a function that registers/dequeues views in example with their class name. I made a post about this here
I just ran into the same problem, and I ended up looking up the view using its tag to edit a label:
UICollectionReusableView *footer = (UICollectionReusableView*)[self.collectionView viewWithTag:999];
UILabel *footerLabel = (UILabel*)[footer viewWithTag:100];
Like you said it is unnecessary to reload an entire section, which cancels out any animation on cells as well. My solution isn't ideal, but it's easy enough.
Swift 3/4/5 version:
collectionView.collectionViewLayout.invalidateLayout()
Caution!
If you change the number of collectionView items at the same time (for example you show the footer only if all cells were loaded), it will crash. You need to reload the data first, to make sure that the number of items is the same before and after invalidateLayout():
collectionView.reloadData()
collectionView.collectionViewLayout.invalidateLayout()
I got the same problem. I tried #BobVorks's answer and it is working fine, if only the cell was reused else it won't. So, I tried finding a more cleaner way to achieve this and I came up reloading the whole UICollectionView after the performBatchUpdate (completion block) and it is working great. It reloads the Collection Without any cancellation of animation in the insertItemsAtIndexPath. Actually I personally up voted recent 2 answers cause i find it working but in my case, this is the cleanest way to do it.
[self.collectionView performBatchUpdates:^{
// perform indexpaths insertion
} completion:^(BOOL finished) {
[self.collectionView reloadData];
}];
[UIView performWithoutAnimation:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:4]];
}];
[UIView performWithoutAnimation:^{
[self.collectionView reloadData];
}];
Here are two ways you could do it.
1.
Create a mutable model to back the data that will eventually be available. Use KVO in inherited class of UICollectionReusableView to observe the changes and update the header view with the new data as it comes available.
[model addObserver:headerView
forKeyPath:#"path_To_Header_Data_I_care_about"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:NULL];
then implement listener method in header view
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
2.
add notification listener to the view and post a notification when the data has successfully come available. Downside is that this is application wide and not a clean design.
// place in shared header file
#define HEADER_DATA_AVAILABLE #"Header Data Available Notification Name"
// object can contain userData property which could hole data needed.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(headerDataAvailable:) name:HEADER_DATA_AVAILABLE object:nil];
[[NSNotificationCenter defaultCenter] postNotificationName:HEADER_DATA_AVAILABLE object:nil];
let headerView = collectionView.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionHeader)[0] as! UICollectionReusableView
I've used above method to get current header, and successfully updated subviews on it.
Here's what I did to update only the section headers that are currently loaded in memory:
Add a weakToStrong NSMapTable. When you create a header, add the header as the weakly held key, with the indexPath object. If we reuse the header we'll update the indexPath.
When you need to update the headers, you can now enumerate the objects/keys from the NSMapTable as needed.
#interface YourCVController ()
#property (nonatomic, strong) NSMapTable *sectionHeaders;
#end
#implementation YourCVContoller
- (void)viewDidLoad {
[super viewDidLoad];
// This will weakly hold on to the KEYS and strongly hold on to the OBJECTS
// keys == HeaderView, object == indexPath
self.sectionHeaders = [NSMapTable weakToStrongObjectsMapTable];
}
// Creating a Header. Shove it into our map so we can update on the fly
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
PresentationSectionHeader *header = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"presentationHeader" forIndexPath:indexPath];
// Shove data into header here
...
// Use header as our weak key. If it goes away we don't care about it
// Set indexPath as object so we can easily find our indexPath if we need it
[self.sectionHeaders setObject:indexPath forKey:header];
return header;
}
// Update Received, need to update our headers
- (void) updateHeaders {
NSEnumerator *enumerator = self.sectionHeaders.keyEnumerator;
PresentationSectionHeader *header = nil;
while ((header = enumerator.nextObject)) {
// Update the header as needed here
NSIndexPath *indexPath = [self.sectionHeaders objectForKey:header];
}
}
#end
This question is very old but a simple way to do it is to just set a delay that covers the time your view is animating and disabling the animation while you update the view...usually a delete or insert takes about .35 seconds so just do:
delay(0.35){
UIView.performWithoutAnimation{
self.collectionView.reloadSections(NSIndexSet(index: 1))
}
My problem arose when frame sizes for the supplementary views changed upon invalidating the layout. It appeared that the supplementary views were not refreshing. It turns out they were, but I was building the UICollectionReusableView objects programmatically, and I was not removing the old UILabel subviews. So when the collection view dequeued each header view, the UILabels would pile up, causing erratic appearance.
The solution was to build each UICollectionReusableView completely inside the viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath method, starting by a) removing all subviews from the dequeued cell, then b) getting the frame size from the item's layout attributes to allow adding the new subviews.
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
yourClass *header = (yourClass *)[collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:#"identifier" forIndexPath:indexPath];
[[header viewWithTag:1] removeFromSuperview]; // remove additional subviews as required
UICollectionViewLayoutAttributes *attributes = [collectionView layoutAttributesForSupplementaryElementOfKind:kind atIndexPath:indexPath];
CGRect frame = attributes.frame;
UILabel *label = [[UILabel alloc] initWithFrame: // CGRectMake based on header frame
label.tag = 1;
[header addSubview:label];
// configure label
return header;
}
I have got a Perfect solution:
let footerView = self.collectionView.visibleSupplementaryViews(ofKind: UICollectionView.elementKindSectionFooter)
Now you can access all subview of footerView by using:
footerView[0].subviews[0]
If you have label in your footerView then :
let label: UILabel = footerView[0].subviews[0] as? UILabel ?? UILabel()
Final Step:
label.text = "Successfully Updated Footer."
if let footerView = collectionView.subviews.first(where: {$0 is LoadingFooterCell}) as? LoadingFooterCell {
footerView.isLoading = .loading
}