Change button class conditionally based on OData Model - sapui5

I have a basket, each line containing a button with a tooltip which displays if any internal or Supplier Notes haves been entered.
Here's the view code:
<Button text="" icon="sap-icon://notes" tooltip=" {i18n>ReviewBasket.SupplierNote}: {basket>SupplierNote} {i18n>ReviewBasket.InternalNote}: {basket>InternalNote}" press="openSupplierNote"/>​
This is great, but I want to change the type of the button to Emphasized if either internal or supplier notes exist.
I've so far logged the model data, which contains all the info.
OData: Object
items: Array[1]
0: Object
SupplierNote: "Test1
InternalNote: "Test2"
Any suggestions?

You can set the button type with an expression binding.
<Button
icon="sap-icon://notes"
type="{= (${basket>InternalNote} === '' && ${basket>SupplierNote}) ? 'Accept' : 'Emphasized'}"
press="openSupplierNote"/>

Related

How to set visible property as false if model does not yet defined? (SAPUI5)

my model "categories" is defined on the second view controller and set as a global model. but in the first view, I have a button and set its visible condition like below
<Button text="Click Me" visible="{=${categories>/}.length > 0}" />
the button should only be visible when the categories model has data.
but since I have not yet navigated to the second view and my model is not yet defined. the expression binding is not working for the button in the first view. how do set the button visible as false if the model is not defined and has no data? only using XML, not with javascript.
/}.length > 0}" />
According the Expression Binding Documentation, you can use Function call and Binary logical operator.
With that, you can for example do this expression binding:
{= Array.isArray(${model}) && ${model}.length > 0 }
Check model exists and is an Array
And
Check model size > 0
With that if model is not existent or is not an array or is an empty array the answer is false otherwise true.
With you code it would give :
<Button text="Click Me" visible="{= Array.isArray(${categories>/}) && ${categories>/}.length > 0 }" />
& character from binary operator must be escaped in XML with &
XML syntax escaping rules

Quasar2 Vue3 Cypress q-popup-edit

I have the following vue template:
<template>
<q-item tag="label" v-ripple>
<q-popup-edit
v-model="model"
:cover="false"
fit
buttons
:validate="validate"
#before-show="modelProxy = model"
>
<template v-slot:title>
<div class="text-mono">
{{ name }}
</div>
</template>
<q-input
color="indigo"
v-model="modelProxy"
dense
autofocus
counter
:type="dataType ? dataType : 'text'"
:hint="hint"
:error="error"
:error-message="errorMessage"
/>
</q-popup-edit>
<q-item-section>
<q-item-label class="text-mono">{{ name }}</q-item-label>
<q-item-label v-if="offset && model && model.length > offset" caption
>...{{
model.substring(model.length - offset, model.length)
}}</q-item-label
>
<q-item-label v-else caption>{{ model }}</q-item-label>
</q-item-section>
</q-item>
</template>
I would like to perform E2E test using Cypress with the following code snippet:
it('Verify Edit Box from auto-generated page', () => {
cy.get('[data-test="popup-edit-setting-1"]').contains("Auto Generated Edit box");
cy.get('[data-test="popup-edit-setting-2"]').contains("Auto Generated Edit box (Number)");
cy.get('[data-test="popup-edit-setting-1"]').should("be.enabled"); // XXX
cy.get('[data-test="popup-edit-setting-1"]').focus().click().type("Hello");//.click("SET");
cy.get('[data-test="popup-edit-setting-1"]').find("label").should('have.value', 'Hello') // XXX
});
It stumbles on the XXX points.
#Fody's solution works but there is one minor issue. I have 2 popup edit box. One with normal string, another with only numeric. There are 2 test cases for the numeric popup editbox. One with invalid normal string entry and another with valid numbers. The problem is that at the end of the test, the numeric popup edit box does NOT return to display mode. It stays popup.
This is the way I would test q-popup-edit. I used a generic example, yours may differ in some details.
I aimed to test based on what a user sees rather than any internal class or internal properties.
The user story is:
the text to be edited has a "hand" pointer when hovered
click on it to change it from "display" mode to "edit" mode
the input is automatically focused, user can start typing
user enters some text
user clicks away and the input loses focus, goes back to "display" mode
// activate popup editor
const initialText = 'Click me'
cy.contains('div.cursor-pointer', initialText) // displayed initial text
.should('be.visible') // with hand cursor
.click()
// initial condition
cy.focused() // after click <input> should have focus
.as('input') // save a reference
.should('have.prop', 'tagName', 'INPUT') // verify it is the input
cy.get('#input')
.invoke('val')
.should('eq', initialText) // displayed text is also in the input
cy.contains('8').should('be.visible') // character count
// edit action
cy.get('#input')
.clear()
.type('test input')
cy.get('#input')
.invoke('val')
.should('eq', 'test input') // verify input
cy.contains('10').should('be.visible') // character count has changed
// back to display mode
cy.get('body').click() // go back to display mode
cy.contains('div.cursor-pointer', 'test input')
.should('be.visible')
.and('contain', 'test input') // verify display element
cy.contains('10').should('not.exist') // edit counter has gone
Notes
To start the edit, you need to identify the display-mode element. It's easiest if you have some unique text in the field, so try to arrange that in the page initial data.
If no unique text, look for a label or some other selectable element nearby then navigate to it.
If you add a data-cy attribute to the <q-popup-edit>, it will not exist in the DOM until the component enters edit-mode (so you can't use it in the initial click()).

How can I test if a html input type radio is checked

I have this HTML in my component.html:
<input type="radio" [checked]="selected" (change)="select()" />
How can I make a Spectator query and expect to test if this input element is checked or not?
I have tried with:
expect(spectator.query('input')).toHaveAttribute('checked');
But I get the error:
Error: Expected element to have attribute 'checked', but had 'undefined'
And I have tried with:
expect(spectator.query('input')).toBeChecked();
But then I get the error:
Error: Expected element to be checked
How can I test this simple HTML input element?
Thank you
Søren
expect(spectator.query('input')).toBeChecked(); is the correct usage.
It looks like selected property is false due to which radio button is not selected and you are getting this error. Simple fix you binding in test (by setting selected to true) or update assertion to check if radio button is not selected:
expect(spectator.query("input[type=radio]")).not.toBeChecked();
Take a look at this stackblitz code sample where I have 2 bound radio buttons one selected and another not selected and I have tests for it.
it("should be checked", () => {
spectator = createComponent();
expect(spectator.query("#r1[type=radio]")).not.toBeChecked();
});
it("should not be checked", () => {
spectator = createComponent();
expect(spectator.query("#r2[type=radio]")).toBeChecked();
});
Also, take a look at this guide to see available custom matchers.

How to synchronize control values within different views

I would like to know how to get the content of TextArea, assign the value to a variable, set it to a model, and then set the variable to another TextArea in another view. I have coded some examples and it works, but not on TextArea.
Here is the example code:
// In init of the Component.js
this.setModel(new JSONModel(), "TransportModel"); // JSONModel required from "sap/ui/model/json/JSONModel"
// In *.controller.js
this.getView().getModel("TransportModel").setProperty("/", {
"Serial": this.byId("mat_serial").getValue() // "mat_serial" == id of the Input box in XML view
});
In the last step, I set the Text from a different View (also XML and Input Box) with the Value of the Model Element.
<Text text="{TransportModel>/Serial}" />
That worked pretty well.
But how to do the same with the TextArea? How can I do it based on this model? The value that I want to use from the first TextArea should also be on a TextArea in another view.
UI5 supports two-way data binding. I.e. if the user changes something in the UI (e.g. user types something in the text area), that change will be reflected automatically in other bindings that listen to the change.
<!-- In view 1 -->
<TextArea value="{TransportModel>/Serial}" />
<!-- In view 2 -->
<Text text="{TransportModel>/Serial}" />
No need to get input values by hand. Simply let the framework synchronize the value.
How to use a local json model:
Create
initItemViewModel: function () {
return new JSONModel({
Serial: ""
});
}
this._oViewModel = this.initItemViewModel();
this.setModel(this._oViewModel, "TransportModel");
Using
this.getView().getModel("TransportModel").setProperty("/Serial", serial);
<Text text="{TransportModel>/Serial}" width="auto" maxLines="1"/>

MVC2 Trying to pass multiple parameters to ActionResult based on textbox with dynamic name

I am trying to implement a quantity selector for the number of items added to a shopping cart.
I have a textbox with a dynamic name for each row of items in the catalog. Each row has a "Add to Cart" button.
If I enter the desired quantity in the textbox and click the "Add To Cart" button, I want the entered quantity of the selected item to be added to my Cart.
The controller action that adds the new quantity to the database for the cart is as follows:
public ActionResult AddToCart(int productID, int quant)
{
repository.AddItemToOrder(productID, quant);
return RedirectToAction("Browse");
}
I know that calling the "Browse" action to render the page again is not the most efficient method. I will account for that later.
My question is: How do I make a call to this "AddToCart" controller action with both parameters?
I was able to get a version working with 1 parameter. In this case the second parameter in the above controller action, quant, was removed.
The line in my View was:
<input type="button" onclick="document.location.href = '<%: Url.Action("AddToCart") %>'+'?productID=<%: item.ProductID %>' " value="Add to Cart" />
While this worked, I need to be able to reference the textbox for the quantity.
I tried this next line that includes multiple parameters in my View:
<input type="button" onclick="document.location.href = '<%: Url.Action("AddToCart") %>'+'?productID=<%: item.ProductID %>'+'?quant=<%: item.ProductID %>' " value="Add to Cart" />
The value assigned to "quant" is the same as what is assigned to "productID". I did this to simply get something to work correctly. Once it is working I plan to use the value of the textbox that has a dynamic name. (I need some help with that as well)
When I tested and clicked the button for the row, I received the following error:
The parameters dictionary contains a null entry for parameter 'productID' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult AddToCart2(Int32, Int32)' in 'OER.Controllers.eCommerceController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
You need an ampersand, &, between variables in a querystring, not another ?... simple typo.
/AddToCart?productId=3&quant=1
If you want to give quant a default value, so it is not always required, you can change your action method to something like:
public ActionResult AddToCart(int productID, int quant = 1)
Based on your comments, I would set up a form that the button will submit, instead of squeezing it all into an onclick:
#using(Html.BeginForm("AddToCart")) {
#Html.Hidden("productId", item.ProductId)
#Html.Input("quant")
<input type="submit" value="Add to Cart" />
}
If you want to switch to just a regular link instead of a button, you'll need to wire up some jQuery to pull the quant parameter from the text box on click.
$('.addToCartLink').click(function() { // All the "add to cart" links would have this class
// Pull the product ID (just an example)
var productId = $(this).attr('data-id');
// Set the quantity
var quantity = $('#txtlinequantity-'+productId).val();
// Possible validation here
...
// Hit the action method
window.location = '/AddToCart?productId='+productId+'&quant='+quantity;
});
Don't you want
<input type="button" value="<%: item.ProductID %>" name="productID" id="productID"/>
inside the form you're submitting?
If you have a form element being submitted, MVC will automatically pull the required information and assign it to the equivalent variable in your code behind based on the name field (or id). The value field is the value to assign to the corresponding variable.