I need to change the contents of an AppBar when a user changes the view in a Hub control.
The way I did it while using a Pivot control is listening to the SelectionChanged event and responding to the SelectIndex value.
The hub, however, only has a SectionsInViewChanged event, which returns a collection of multiple sections. Usually the one user is interacting with and then the adjacent, barely-visible section.
So my question is, how can I tell which Section is the one that is currently being prominently displayed to the user (so I can change the AppBar icons accordingly)?
In Hub control, We can listen to the SectionsInViewChanged event. We can get the HubSection which is displayed in screen by this:
var section = hubDemo.SectionsInView[0];
hubDemo is the name of my Hub control. And we can set Tag property for each HubSection. For example:
<Hub x:Name="hubDemo" SectionsInViewChanged="demoHub_SectionsInViewChanged">
<HubSection Tag="0" Header="Section1" Width="800"/>
<HubSection Tag="1" Header="Section2" Width="400"/>
<HubSection Tag="2" Header="Section3" Width="400"/>
<HubSection Tag="3" Header="Section4" Width="400"/>
<HubSection Tag="4" Header="Section5" Width="600"/>
</Hub>
So we can change AppBar content by tag:
private void demoHub_SectionsInViewChanged(object sender, SectionsInViewChangedEventArgs e)
{
var section = hubDemo.SectionsInView[0];
var tag = section.Tag.ToString();
switch (tag)
{
// Change your AppBar by tag
}
}
Related
When I dynamically change img's src attribute, old image is displayed while loading a new one.
I have a component which displays some data: text and image. On click the underlying data is changed (i.e. new data from server). Once click, text is changed immediately, but component displays old image while new one is loaded. When new image is loaded, then it is visually displayed which can take noticeable amount of time.
In real application one can have product details and changing products on button click. All data is replaced immediately but not image.
Problem exists when the component is not destroyed (reused).
I've already tried clear image src after click, but it not worked.
I have simple binding in template
img [src]="img.url" style="width: 300px; height: 300px">
<p>{{ img.text }}</p>
and image change on click
this.img = this.images[1];
You can see sample app here https://stackblitz.com/edit/angular-cojqnf
Is this possible to take more control of this image change process? It would be great to clear image on click and wait for new one with empty background for example.
I hacked around a little with your stackblitz demo, I basically wrapped your code in an ImageGhostDirective to make it reusable. The directive listens to any changes on the src attribute using a MutationObserver to change the style. Using a HostListener on the 'load' event, it reverts the styles back to normal. I start with an opacity of 0 for the first load, followed by an opacity of 0.2 between successive image changes, but this is completely arbitrary and could be replaced by a spinner or any kind of placeholder...
Here is the link to the stackblitz: https://stackblitz.com/edit/angular-image-ghost-directive
<img [src]="'https://loremflickr.com/300/300?random=' + index"
style="width: 300px; height: 300px" imgGhost>
#Directive({
selector: 'img[imgGhost]'
})
export class ImageGhostDirective implements OnDestroy {
private changes: MutationObserver;
constructor(private elementRef: ElementRef) {
this.changes = new MutationObserver((mutations: MutationRecord[]) =>
mutations.filter(m => m.attributeName === 'src').forEach(() => this.opacity = 0.2)
);
this.changes.observe(this.elementRef.nativeElement, {
attributes: true,
childList: false,
characterData: false
});
}
ngOnDestroy(): void {
this.changes.disconnect();
}
#HostBinding('style.display') display = 'block';
#HostBinding('style.opacity') opacity = 0;
#HostListener('load')
onLoad(): void {
this.opacity = 1;
}
}
It is also possible to tell Angular to automatically attach this directive to every img element by using the img:not([imgGhost]) selector in the directive decorator. That way, you don't have to manually place the directive on every image in your app.
Hope this is useful.
Finally I achieved what I want by leveraging (load) event on img and [ngStyle].
In template I added load handler and style:
<img [src]="img.url" style="width: 300px; height: 300px" (load)="loaded()"
[ngStyle]="{'display': imgVisible ? 'block' : 'none'}">
In back-end:
imgVisible = true;
and when changing data, also hide image:
this.imgVisible = false;
next, when image is loaded, show the image (be careful! when old and new images have the same URL, this event is not raised; if it is the case you need to conditionally hide image)
loaded(): void {
this.imgVisible = true;
}
Complete code for solution: https://stackblitz.com/edit/angular-ewptj7
I'm not a big fan of this kind solutions. It could be difficult to apply when you have more images.
All better solution are welcome.
I have a RadTabStrip being used as a menu (the tabs act as links), some tabs when clicked open a sub-menu for related links.
I have the following code to highlight the current tab being visited:
Master Page Code-behind
protected void Page_Load(object sender, EventArgs e)
{
RadTabStrip tabControl = FindControl("radTabMenu"); //Pseudo
RadTab currentTab = tabControl.FindTabByUrl(Request.Url.PathAndQuery);
if (currentTab != null) currentTab.Selected = true;
}
Master Page
<telerik:RadTabStrip ID="radTabMenu" runat="server">
<Tabs>
<telerik:RadTab Text="Home" NavigateUrl="~/" /> <!-- Loads Default.aspx -->
<telerik:RadTab Text="Menu Item" NavigateUrl="~/MenuItem.aspx" />
<telerik:RadTab Text="Top Level Nav">
<Tabs>
<telerik:RadTab Text="Lower Menu Item 1" />
<telerik:RadTab Text="Lower Menu Item 2" NavigateUrl="~/Location/Page.aspx" />
</Tabs>
</telerik:RadTab>
</Tabs>
</telerik:RadTabStrip>
On page load if I have clicked Menu Item tab to load MenuItem page, the RadTabs correctly highlights the tab. However, I'm not sure how to go about making sure the sub-tab gets highlighted correctly.
I'm trying this, but I'm a little stuck:
RadTabStrip tabControl = FindControl("radTabMenu"); //Pseudo
RadTab currentTab = tabControl.FindTabByUrl(Request.Url.PathAndQuery);
if (currentTab != null)
currentTab.Selected = true;
else
{
string dir = Request.Url.GetComponents(UriComponents.Path, UriFormat.SafeUnescaped);
currentTab = tabControl.FindTabByValue(dir);
if (currentTab != null)
//Trying to findByUrl isn't possible here because the parent tab doesn't have that method.
}
Is there a good alternative to finding by URL, or a faster method overall of reaching the parent and sub-tabs?
EDIT: Adding a picture to clarify what I'm trying to achieve after page navigation
The FindTabBy* methods are available at either RadTabStrip or RadTabCollection level.
That's why, once you find the parent tab you were not able to invoke the FindTabBy* method on it, because you need to invoke the method on its .Tabs property instead.
See an example below:
var parent = radTabMenu.FindTabByText("Top Level Nav");
parent.Selected = true;
var child = parent.Tabs.FindTabByText("Lower Menu Item 1");
child.Selected = true;
Revisiting this, well after having my team decide to remove nested tab menus, I found that the tabs would be selected by URL.
My issue was that the parent tab wouldn't open and be selected, but digging through documentation led me to use tab.Select Parents() which goes up the hierarchy selecting all parents that lead to the current selected tab.
It seems super obvious now that I've found it.
What is the code to check if mouse is clicked inside a child element when the click event is for parent element. I need to differentiate to perform certain tasks only if the click is inside the child element. What kind of propagation happens in flex? I am bit new to this.
I have a video player with video display and video controls bar. I register click event for video player which occupies the full screen. On click the controls bar should toggle (as programmed) which it does, but on clicking any element in the control bar the entire bar dissapears.
<!-- Player Container -->
<s:BorderContainer width="100%" height="100%"
backgroundAlpha="0"
borderVisible="false">
<s:VideoPlayer id="vid_player"
width="100%" height="100%"
verticalCenter="0"
horizontalCenter="0"
skinClass="Skins.VideoPlayerSkin"
maintainProjectionCenter="true"
mouseDown="hideControls(event)"
autoPlay="true" source="{current_video.getSource()}"/>
</s:BorderContainer><!-- Player Container -->
public function hideControls(event:Event):void {
hidePlaylist();
toggleElem(header);
toggleElem(sec_drop_container);
toggleVideoPlayer();
}
public function toggleVideoPlayer() {
var controls:Object = vid_player.videoDisplay.parent.getChildAt(1);
if(controls.visible)
controls.visible=false;
else
controls.visible = true;
}
Probably the simplest way is:
private function mouseHandler(event:MouseEvent/*was e:MouseEvent*/):void {
whateverObject.hitTestPoint(event.stageX, event.stageY, false); // use shape flag is 3rd argument
}
When an item is being dragged from/within a list in the default implementation, it is shown as selected during the drag (and a separate item renderer, in dragging state, is shown as the drag image), so:
<s:ItemRenderer>
<s:Label text="{data}" color.selected="0xFF0000" color.dragging="0x00FF00" />
</s:ItemRenderer>
renders as:
Is there a straightforward way to change the state of the source of the drag (the red, selected, "Bar") to something other than "selected" for the duration of the drag?
In the ideal, I would add color.dragSource="0x0000FF" to the item renderer code above, and "Bar" would be red while selected, but blue once the dragging had begun. When the drag was complete, it would revert to red (or, if no longer selected, black).
What if you did an eventListener on drag start that set the selected item in the list to -1? -1 says that nothing should be selected.
Edit: added below code to support:
<s:List id="myList" dragStart="startDrag(event)"/>
private var dragIndex:int;
private function startDrag(e:Event):void
{
dragIndex = myList.selectedIndex;
myList.selectedIndex = -1;
}
private function stopDrag(e:Event):void
{
myList.selectedIndex = dragIndex;
}
I am creating one application. In that There is one popup, in that I had used one VGroup in one Scroller.
I am dynamically adding my custom components in VGroup and removing all components at the closing of the popup and saves those components in Memory Pool.
In First step, I open a popup with numbers of components by that scroll bar appears.
Then I close the popup.
In second step, I opens a same popup instance with some less components so scroll bar does not appears and close the popup.
And now when I open popup with more components again scrollbar not appears.
So whenever popup is once opend with less components, scrollbar disappears.
Pls help me...
Here is the full code :
<s:Scroller id="myScroller"
width="100%"
height="210"
horizontalScrollPolicy="off">
<s:VGroup id="myContainer"
width="100%"
height="210" />
</s:Scroller>
Code for Adding Components :
for each(var object:MyObject in _arr)
{
var newView:MyCustomView = MyCustomViewPool.acquire();
myContainer.addElementAt(newView, 0);
newView.myData = object;
}
Here is the code for removing components :
for(var i:int = 0; i < myContainer.numElements; i++)
{
var newViewElement:IVisualElement = myContainer.getElementAt(i);
var myViewComponent:MyCustomView = newViewElement as MyCustomView;
MyCustomViewPool.release(myViewComponent);
}
myContainer.removeAllElements();
I think you don't have to set the hight on the VGroup. Just remove the assignment.