Can you override content in the "static content" block when extending classes in geb? - geb

I have 2 classes one extends the other they are listed below:
class TabledPage extends Page {
static content ={
table {$(By.xpath("//tbody"))}
headers {$(By.xpath("//thead"))}
}
Navigator gatAllRows(){
return table.children()
}
Navigator getRow(int index){
return table.children()[index]
}
Navigator getRow(String name){
return table.children().find{it.text()==name}
}
Navigator getColumn(Navigator row, int column){
return row.children()[column]
}
}
and this class which extends the above class:
class somePage extends TabledPage{
static content ={
table(required: false){$(By.xpath("//table[contains(#class,'w-100 table-striped wi-table-hover')]//tbody"))} // I want this to overwrite the table def in TabledPage
}
}
So in the app I am testing most of the pages only have 1 table, but in some cases there are 2 tables (one is hidden depending on screen size) so I want to be able to override the table definition in this case to point to a specific table, can I do this without also overriding the getRow methods or would those need to be overridden as well?
Just to give an example of how I am calling this alswell:
at SomePage
getRow(0)
this works but it uses the TabledPage definition of the table Navigator instead of the somePage definition and I am wondering if there is a way for me to make it use the other definition

Would it work if you changed the content from the Spec instead of from the page? This is how I'm using dynamic selectors in a page:
static content=
{
quantityField{$("$quantitySelector")
}
void setSelectors(tableIndex, row)
{
quantitySelector="#offerDtos$tableIndex\\.segments$row\\.quantity"
}
In my spec, I just call setSelectors with the appropriate values.

Related

How to use static methods in view templates

I want to use static class constants in my view template
Javascript
class FilterModel {
static const FILTER_TYPE_STRING() {
return 'string';
}
}
HTML
<div show.bind="selectedFacet.type===FilterModel.FILTER_TYPE_STRING">
</div>
Short answer: the binding language does not support that.
I met the problem before, but didn't find a good workaround. In such case, I usually define a constant, which the class would set the value from in the constructor and add a comment to show it should be static.
const _filterTypeString: string = 'string';
export class FilterModel {
/*static*/ filterTypeString: string = _filterTypeString;
}
Longer answer: static members in JavaScript are being transpiled directly into the class, not into the prototype, so instances do not have reference to it. The difference is:
class MyClass {
instanceMember: number = 256
static staticMember: number = 1024;
}
//referencing them:
MyClass.prototype.instanceMember
MyClass.staticMember
Everytime when you create an object instance, it creates a copy of the prototype, so that this would have equal values to the prototype. That's what Aurelia does also, creates an instance, when creating a view-model.
In the view template, you can only access members of that object, which is inherited from the prototype. Since the static method is not a member of that object, you cannot access it. Of course, you might create a reference, but I found this workaround more annoying than the one above. With code example:
export class FilterModel {
static filterTypeString: string = 'string';
refToFilterTypeString = FilterModel.filterTypeString;
}
HTML:
<div show.bind="selectedFacet.type === refToFilterTypeString">
</div>

Decorator pattern issue - how to call nested decorators methods?

I'm now studying the decorator pattern, here some example code (PHP) :
abstract class component{
public function drawShape(){};
}
class concreteComponent extends component{
public function drawShape(){//code};
}
class decoratorComponent extends component{
private $component;
public function __construct($component){ $this->component=$component; }
public function drawShape(){
$this->component->drawShape();
}
}
class borderDecorator extends decoratorComponent{
public function drawShape(){
$this->drawBorder();
$this->component->drawShape();
}
public function setBorder(){};
public function drawBorder(){};
}
class bgColorDecorator extends decoratorComponent{
public function drawShape(){
$this->drawBgColor();
$this->component->drawShape();
}
public function setbgColor(){};
public function drawBgColor(){};
}
Ok, now:
$test=new concreteComponent();
$border=new borderDecorator($test);
$border->setBorder(10);
$bgColor= new bgColorDecorator($border);
$bgColor->setBgColor(#000);
Now I have a component decorated with a #000 bg color and a 10(some unit) border.
With
$bgColor->drawShape();
it means drawBgColor + drawBorder + drawShape and all right, BUT:
How can I modify or remove the border??
$bgColor-> ???
The bgColor class can't access directly the border methods...
Thanks
From what I understand you have chained your decorators in a way that leaves out a bgColorDecorator instance from which you cannot set/remove the borders.
What you should do is to change the order of construct and finish by the borderDecorator part :
$test=new concreteComponent();
$bgColor= new bgColorDecorator($test); // pass test to bgcolor
$bgColor->setBgColor(#000);
$border=new borderDecorator($bgColor); // pass bgcolor to border
$border->setBorder(10);
// You can now set/remove border on $border
// and of course : $border->drawShape();
It seems that your task is to render an object so the proper order of drawing should necessitate a change in your drawShape methods to keep the order background / shape / border
$this->drawBgColor();
$this->component->drawShape();
// will become a post-action
$this->component->drawShape();
$this->drawBgColor();
The problem is now you won't be able to set the backgroundcolor dynamically for the same reason. So the other solution could be to modify your decoratorComponent interface to include what you need and implement it in the decoratorComponent subclasses.
Edit for double border case :
Just chain two borderDecorator to a Component
$cmp = new concreteComponent();
$bDecrtor1 = new borderDecorator($cmp); // 1st border decorator on cmp
$bDecrtor1 ->setBorder(10);
$bDecrtor2=new borderDecorator($bDecrtor1); // 2nd border decorator on 1st one
$bDecrtor2->setBorder(20);
// $bDecrtor2->drawShape();
// You can then use bDecrtor1 or bDecrtor2 to (re)set the border properties
// You can use bDecrtor2 to chain other decorators...
What you could do is implement the magic method named __call() (a catch-all method), to try to delegate any non-existing method to the wrapped component:
class decoratorComponent extends component{
private $component;
/* ... */
public function __call( $name, $arguments ) {
return call_user_func_array( array( $this->component, $name ), $arguments );
}
}
You'll just have to build in safeguards to catch the cases where the method you're trying to call ultimately doesn't exist in any component down the line.
However, you should probably also evaluate whether it is even desirable to call the decorator methods after you have already wrapped them in another decorator.

Change ViewModel default data strictly from server in MVC?

I know this is a weird one but bear with me. I need to set a default state/value for form inputs on a portion of my application.
In my "MainController" I pull up a portion (or 'wrapper' of sorts) page and then pull partial views from this main page. Here's a pseudo-code example:
User goes to Main ->
MainController/Index Called
-> User clicks Link A ->
AJAX .load() pulls html from PartialViewA into #partialContainer
-> User clicks Link B ->
AJAX .load pulls html from PartialViewB into #partialContainer
Here's the AJAX call:
$("#mainPanel").load('#Url.Action("GetModule","Settings")' + '?partialName=' + moduleName);
...and the corresponding server-side action that handles it:
public ActionResult GetModule(string partialName)
{
return PartialView(partialName);
}
It works great for me, each of the modules has plenty of form fields on them, all interacting well with one another and server so that isn't my problem. The issue is setting default values from the dbase for the form fields contained in the partial views.
For instance the "General" partial has many checkboxes which will determine how portions of the application display. I want to pull from the database the pre-exisiting boolean value and when the partial gets pulled from GetModule(), have these values defaulted.
I've taken a look around and I'm afraid the way that I am pulling the partial's into the main page may be the issue. I thought I could build the defaults into the constructor like so:
public class GeneralViewModel
{
public GeneralViewModel()
{
var Data = from m in dataContext.Table
where m.UserID == _id
select new
{
m.Data1,
m.Data2,
};
foreach(var setting in Data)
{
Checkbox1 = Convert.ToBoolean(setting.Data1); // Conversion from bool? to bool
Checkbox2 = Convert.ToBoolean(setting.Data2); // Conversion from bool? to bool
}
}
public bool Checkbox1 { get; set; }
public bool Checkbox2 { get; set; }
}
But it would appear the constructor never gets called. That sort of makes sense, except when you consider the fact that my form fields are not only rendering properly, but communicating with the database just fine as well. So the question is, what am I doing wrong? Is it the way I call the Partial's or am I missing something with assigning values to my VM values?
As always, thanks SO!
I think it's better to have different action methods for rendering the partial views, but for your case, i think this solution would work.
Have a Model that contains the other view models
public class ViewModel
{
public ViewModel1 ViewModel1 { get;set;}
public GenereViewModel General {get;set;}
}
Then in your controller you could initialize the viewmodel based on the partial name.
public ActionResult GetModule(string partialName)
{
var model = new ViewModel();
switch (partialName)
{
case "General": model.General = InitializeGeneral();
break;
case "ViewModel1": model.ViewModel1 = InitializeViewModel1(); break;
}
return PartialView(partialName, model);
}
private GeneralViewModel InitializeGeneral()
{
// initalize then return model
}

Pattern for passing common data to _layout.cshtml in MVC4.5

I am trying to come up with the best pattern for passing data to my _layout.cshtml page.
I am toying with creating a common base class from which all view specific models derive. This base class would be recognized by my _layout.cshtml and used to fill in details about the user and load proper images in the header, etc. For example, here is a snippet of it.
public abstract class ViewModelBase
{
public string Username { get; set; }
public string Version { get; set; }
}
At the top of my _layout.cshtml I have...
#model MyProject.Web.Controllers.ViewModelBase
I need a common area to hydrate the information required by the model, and am planning to use the following pattern...
Each action method creates and hydrates a model derived from
ViewModelBase.
The action completes.
I create a ActionFilterAttribute and override OnActionExecuted to cast the
current Result to ViewModelBase.
If the conversion is successful, then I populate the ViewModelBase details with the relevant data.
Here are my questions...
Is the use of a ActionFilterAttribute (OnActionExecuted) a good pattern for what I am trying to do?
I am not able to see how to get the Result created in the action from the HttpActionExecutedContext. How is this done?
I follow the same approach and use a base ViewModel class which all my other viewModels inherit from.
Then, I have a base controller that all controller inherit from. In there, I have one method that takes care of initializing the view model:
protected T CreateViewModel<T>() where T : ViewModel.BaseViewModel, new()
{
var viewModelT = new T {
HeaderTitle = "Welcome to my domain",
VisitorUsername = this.VisitorUsername,
IsCurrentVisitorAuthenticated = this.IsCurrentVisitorAuthenticated,
//...
};
return viewModelT;
}
Then on each controller, when I want to create the view model, I simply call the base controller's method:
var vm = base.CreateViewModel<MyPageCustomViewModel>();

Creating a simple controller alias

I'm not sure I am using the proper terminology, so I will describe what I want to achieve.
I have a controller called ControllerA and want a "virtual" controller called ControllerB to function exactly the same as ControllerA.
Basically I just want the url site.com/ControllerB to load up the same page as site.com/ControllerA (but not redirect).
Hope my description is clear enough.
You can achieve what you want with a simple URL rule:
'controllerA/<a>' => 'controllerA/<a>',
'controllerB/<a>' => 'controllerA/<a>',
Read more about URL rules here: http://www.yiiframework.com/doc/guide/1.1/en/topics.url#user-friendly-urls
You can extend ControllerA with ControllerB and provide extended controller name. Next override getViewPath method. Attribute extendedControler give us basic controller name.
class ControllerBController extends ControllerAController
{
private $extendedControler = 'ControllerA';
public function getViewPath() {
$nI = Yii::app()->createController($this->extendedControler);
return $nI[0]->getViewPath();
}
}
Of course you can use some string modification. Like str_ireplace:
class Klient2Controller extends KlientController
{
public function getViewPath() {
//We must extract parent class views directory
$c = get_parent_class($this);
$c = str_ireplace('Controller', '', $c); //Extract only controller name
$nI = Yii::app()->createController($c);
return $nI[0]->getViewPath();
}
}