Aurelia #observable property, avoid get called when attaching to view - aurelia

I have tried to search the world wide web for answers, but can't find any.
I have property in Aurelia like this:
#observable
public _name: boolean = false;
Then uses Aurelias *Changed like this:
public async _nameChanged(): Promise<void> {
//Do stuff
}
Then in the html uses it something like this:
<div value.bind="_name"></div>
Now the question is, how in the world do I do to avoid getting the change method to get called when it is attaching to the viewmodel?
Or to but it simple, is there anyway to configure the Change listener to only listen to changes from the view. Because I am trying out a kind of "autoSaveFeture". And I only want the Change to happen if the user triggers the change from the view.
I do have a solution but that means I have to go away from the aurelia frameworks observable. But before I do that I would like to know if there is any solutions out there that I can't find or is not documented.
Like you could set settings on the #observable flag to only litsen to changes that has triggerd by the view..
If there is any question or Im describing the problem bad please let me know.

Related

Initialize WebElements for part of a page

I'm following the Page Object model approach. I’m working on implementing a SearchResultsPage where a bunch of search results are displayed. In thinking about this page, I would like to implement it in such a way that it would support a getSearchResultByIndex(int index) method. Ideally, I would like the return type of this method to be a SearchResult, which would be a mini-page object (aka panel) that encapsulates the functionality found on a search result item since there are a number of attributes of a search result that the user can interact with. I don’t see how to accomplish this though. I was hoping to find a method like PageFactory.initElements() that would take in the WebDriver, a WebElement or selector (that identified an individual search result), and an instance of my SearchResult, but haven’t seen anything.
For clarity. Here's the basic structure of a SearchResults page.
<div class="searchResultsContainer">
<div class="searchResult">various internal fields to interact with/inspect</div>
<div class="searchResult">various internal fields to interact with/inspect</div>
...
<div class="searchResult">various internal fields to interact with/inspect</div>
</div>
It seems like this has to be a common problem out there that people have solved. I've used this "panel" notion for other common page elements like header, footer, etc, but never in the case where multiple instances of the same panel type are on the same page.
Any thoughts would be appreciated. Thanks.
If it were me I would approach it differently. I would split this into 2 page object classes. One for SearchResults, and one for SearchResultPage. The SearchResults would be the generic results list and actions you can take on those results. Within that class you would add a method to click on an individual search result, to pop up the details of that result, that would be what returns your SearchResultPage object.
Here is a rough sketch of what that method could look like inside your SearchResults page object. Not sure what language you are using but this is in C# (Java would be similar, Python much different but you'll get the general idea):
public SearchResultPage GetSearchResult()
{
// do something to click and show search details
return new SearchResultPage(_driver);
}
And then a skeleton of the SearchResultPage class object itself:
public class SearchResultPage
{
IWebDriver _driver;
// add whatever elements you want to work with specific to that single record view
//constructor
public SearchResultPage(IWebDriver driver)
{
_driver = driver;
}
// add whatever methods you want to interact with the elements in that view
}
The good thing about keeping the page objects separate in this case is SearchResults could actually be used in other areas of the application as well, if there are results on other pages that use the same elements etc. I find myself taking out common page elements (drop down menus, grids, etc) into their own objects all the time. Otherwise you end up repeating a lot of code if you stick to strict Page Object model where common functionality exists on multiple pages.
I think I've got this solved. I ended up abandoning PageFactory.initElements(), which I think I've learned is really key and likely an old-school way of implementing the page/object model. Adopting the use of By rather than FindBy seems to work much better as long as the appropriate conditional WebDriverWait.until(ExpectedConditions.elementToBeClickable(elementLocator)) is used.
After coming to this understanding, introducing the concept of a panel locator in my base Panel class allowed me to combine that locator with a nth-of-type(idx) locator to get things wired up and working as expected. Here's a simplified example of that in use in my SearchResultsPage:
public SearchResult getSearchResult(int idx) {
SearchResult res = new SearchResult(getWebDriver(),
By.cssSelector(".searchResultsContainer .seachResult:nth-of-type(" + idx + ")"));
return res;
}
My SearchResult class then just has a number of By locators defined that essentially call new ByChained(panelLocator, locator);
So glad to have solved this!

Create a View Component template/container that accepts HTML or other components as parameters

I have searched many places and have not seen anything similar to what I am thinking.
Let's say I want to create a reusable container component, like a card, form, or a modal, and save that as a View Component. How would I add a new view components inside of the "body" of that main View Component in a way that would make it maximally reusable?
The syntax here is just to demonstrate the idea of course, but for example, something like this:
<vc:parent var1="x" var2="y">
<vc:child var3="a" var4="b"></vc:child>
<vc:child var3="c" var4="d"></vc:child>
</vc:parent>
Is anything like this possible?
This doesn't necessarily need to use View Components—maybe partial views?—so long as the primary goal of reusing the containers of other reusable elements is achieved.
I have looked into helpers, but they are no longer available in ASP.NET Core.
So I figured out how to do it.
I used part of this tutorial about helpers: Templates With Razor
And modified it so it works with ViewComponents.
So to get it working, in a minimal example, create a ViewComponent class as such:
[ViewComponent(Name = "Test")]
public class VCTest : ViewComponent
{
public IViewComponentResult Invoke(Func<dynamic, object> Content)
{
return View(Content);
}
}
Create the actual template that you want, in a cshtml file like this:
#model Func<dynamic, object>
<div id="SomeTemplateTest">
#Model(null)
</div>
In this very simple case I just used the Func as model since there is only one parameter, but for more parameters you'd just have to call #Model.funname(null) instead of just #Model(null). No big deal.
when calling this component from your view, create your child elements beforehand like so:
#{Func<dynamic, object> children=
#<div>
<vc:child var1="a" var2="b"></vc:child>
<vc:child var1="c" var2="d"></vc:child>
<vc:child var1="e" var2="f"></vc:child>
</div>;}
The div is there only to encapsulate all the elements. I haven't found a way around that but it has no major implications.
Then call the parent ViewComponent tag passing on the parameters accordingly:
<vc:test content="children"></vc:form-test>
And that's it, worked perfectly. It is unfortunate that I could not find a more seamless way. But this does the job.
If anyone knows of a better alternative I'd love to know more.

Aurelia routing to the same moduleID

Hi there I have asked this on Gitter, but hope that someone here may be able to help.
I have two different routes that have the same moduleId. I have also set up a setting object within the routes with some data to differentiate what gets rendered. Everything works fine when I navigate to one of these routes from somewhere else, but if I navigate from one to the other neither the constructor or the activate are fired. am i missing something??
I had this problem and it took me a while to find a solution - this should help you I hope;
You need to add the determineActivationStrategy() method into your class, and then return as below.
import {activationStrategy} from "aurelia-router";
export class ExampleViewModel {
determineActivationStrategy() {
return activationStrategy.replace;
}
}
This will force the VM to be replaced when you're routing to it from itself.
Here's some more info on the different Activation Strategy types;
activationStrategy.no-change – reuse instance with no lifecycle events
activationStrategy.invokeLifecycle – call lifecycle methods on the ViewModel instance each time the route switches
activationStrategy.replace – construct new instance of ViewModel and invoke full lifecycle on it
Taken from here ZombieCodeKill - Aurelia Routing Beyond the Basics
Found the answer here :) Although not a complete fix out of the box, the implementation is possible

How to use GWTP for a ListView (Widget)?

I started to use GWTP for my project and I'm currently re-writing all my code to let it work with this library.
However, I struggle to understand how I use GWTP if I want e.g. a ListView with ListItemView items.
#Inject
public ToolsPresenter(PlaceManager placeManager, EventBus eventBus, MyView view, MyProxy proxy) {
super(eventBus, view, proxy, AdminToolPresenter.SLOT_AdminToolMainContent);
this.placeManager = placeManager;
ToolListView toolListView = new ToolListView(...)
ToolListPresenter toolListPresenter = new ToolListPresenter(....);
this.setInSlot(SLOT_ToolList, toolListPresenter);
}
What I want is to place my ListView inside a slot. I am very certain that I can't do what is shown up there but I just don't get how I use just simple Widgets with GWTP.
Or am I doing this completely wrong and I should just extend a Composite for ListView and not use GWTP stuff here at all?
There is a lot of information missing from your question so this is a difficult one to answer.
Assumption 1 - Your GWTP artifacts (ToolListView, ToolListPresenter, ToolListView.ui.xml, and ToolListModule) are setup correctly and ToolListModule is installed in a parent module.
Assumption 2 - You are using GWTP version 1.5+ which has typed slots.
You should not be instantiating your ToolListView or ToolListPresenter.
Simply add:
#Inject ToolListPresenter toolListPresenter;
If you are trying to call the setInSlot method then
Make sure ToolListPresenter is a PresenterWidget
Make sure your slot is not a NestedSlot.
Finally try moving the call to setInSlot outside of your constructor and into the overridden onBind() method.

How to access a component bound to a property in QML

It's come up several times that I have wanted to access a property of a component which is bound to another property. I've spent days trying to figure out how to do this and failed. Below is a simple example of what I'm trying to do.
TabView {
Component.onCompleted: console.log(style.frameOverlap)
// OR tvStyle.frameOverlap
style: TabViewStyle {
id: tvStyle
frameOverlap: 5
}
}
Nothing like this works. I'm completely baffled about how to access these members either statically or as an instance. Can someone please explain to me whether something like this is possible?
Thanks.
The short answer is that you need to write:
Component.onCompleted: console.log(__styleItem.frameOverlap)
The longer answer is that the 'style' property is a Component. Component is something that remembers a tree of declarations, and can create objects as needed. However, it does not expose that remembered declaration, so when you try to access the frameOverlap property, it's not there.
In theory, you can call style.createObject to create an object, and examine its properties, but that would create another unnecessary instance, so you can look at TabView.qml, notice that it creates an instance already using Loader, and stores that in a property called __styleItem, and so use the code I gave above.
Of course, accessing internal properties is not a particularly good idea, but might be OK in practice. Ideally, one should be able to instantiate TabViewStyle and bind the instance to the style property, with TabView figuring out whether it's Component or object, but I'm not sure it's possible.