I want to add required attribute in MUI TextField based on a condition - material-ui

I want to add required attribute in MUI TextField based on a condition.
Var flag = false
If (investment>50000 && investment<5000){
flag = true
}
<TextField
required = {flag}
id="shop-name"
label="Shop Name"
variant="outlined" />
This doesn't seems to work

Seems you have your if statement in the wrong way and you wanted the investment number to be between 50000 and 5000. So change it to
if (investment > 5000 && investment < 50000) {
flag = true;
}

Related

Select: Limit number of selected options

I'm using ANT Design's Select component in multiple select mode. After two options are selected (see screenshot) I'd like to prevent any more from being selected. The field should not be disabled, so that you can deselect an option and select another.
I've tried the onFocus event, but it doesn't provide an event that I could use to preventDefault or otherwise keep from opening the dropdown. I've also tried adding a ref and calling blur() whenever the onFocus event is called. This closes the dropdown, but it's still visible for a second.
Does anyone know of a way to accomplish this?
If 3 or more options selected then with a simple condition you can disable other options.
Store selected options in state and while displaying options disable them based on condition.
https://codesandbox.io/s/happy-leftpad-lu84g
Sample code
import React, { useState } from "react";
import { Select } from "antd";
const { Option } = Select;
const opts = ["a11", "b12", "c13", "d14", "e15"];
const Selectmultiple = () => {
const [optionsSelected, setOptionsSelected] = useState([]);
const handleChange = value => {
console.log(`selected ${value}`);
setOptionsSelected(value);
};
return (
<div>
<Select
mode="multiple"
style={{ width: "100%" }}
placeholder="Please select"
onChange={handleChange}
>
{opts.map(item => (
<Option
disabled={
optionsSelected.length > 1
? optionsSelected.includes(item)
? false
: true
: false
}
key={item}
>
{item}
</Option>
))}
</Select>
</div>
);
};
I solved this problem using "open" prop:
const isMaxValues = value.length === limit;
<Select
mode="multiple"
disabled={false}
{...(isMaxValues && { open: false, onDropdownVisibleChange: handleShowError })}
>
{renderOptions()}
</Select>
So you still able to remove/deselect some options
Also you can provide isMaxValues option to renderOptions method and disable Options to be selected(if you need dropdown to be visible)

How can we validate just the mandatory fields in a form in SAP UI5?

I am trying to create a form which has some mandatory fields that requires validation on form submission.
Could anyone suggest me the best possible way to do that in SAP UI5? The mandatory fields are in greater number, thus i don't want to check all fields separately by their ID.
You can do this in two scenarios. While entering a value, or when submitting the form as in your question.
CheckRequired: function(oEvent) {
var aInputs = [this.getView().byId(oEvent.getSource().getId())];
var sError = false;
jQuery.each(aInputs, function(i, input) {
if (!input.getValue() || input.getValue().length < 1) {
input.setValueState("Error");
input.focus();
sError = true;
} else {
input.setValueState("None");
}
});
return sError;
},
This function is to be used with the onLiveChange property. It checks if the control is filled with at least one character.
If you would like to check everything when you press submit. you could use a function like this with your form:
_onSubmitCheck: function() {
var oForm = this.getView().byId("form").getContent();
var sError = false;
oForm.forEach(function(Field) {
if (typeof Field.getValue === "function") {
if (!Field.getValue() || Field.getValue().length < 1) {
Field.setValueState("Error");
sError = true;
}
else {
Field.setValueState("None");
}
}
});
return sError;
},
It will loop over your form controls to check if the getValue() method exists as part of the control. If that returns yes, it wil check if it has a value of at least 1 character.
There are kind of two ways.
add
"sap.ui5": {
...
"handleValidation": true,
to your manifest.json and type & constraints to your inputs
<Input type="Text" value="{path: 'NoFioriValidationsInDefault', type: 'sap.ui.model.type.String', constraints: { minLength:2 }}" valueLiveUpdate="true" enabled="{= ${editView>/nfvid/enabled} && ${editView>/creating}}" visible="true" width="auto" valueHelpOnly="false" maxLength="0" id="inp_cond_nfvid" required="{editView>/nfvid/required}"/>
This gives just visual feedback to the user, if you need the status in your controller you can either iterate over all the inputs and check them by hand, or use https://github.com/qualiture/ui5-validator
Just by calling
var validator = new Validator();
validator.validate(this.byId("form1"));
if (!validator.isValid()){
//do something additional to drawing red borders? message box?
return;
}
in your controller, the view will mark missing required inputs with the ValueState.ERROR (red borders) and tell you if all inputs inside the supplied control are valid.
I am doing it the old-school way. The input fields do get the required=true property and then I loop over all controls found with this property:
// store view ID to compare with control IDs later
var viewId = this.getView().getId();
jQuery('input[required=required]').each(function () {
// control has wrapper with no id, therefore we need to remove the "-inner" end
var oControl = sap.ui.getCore().byId(this.id.replace(/-inner/g,''));
// CAUTION: as OpenUI5 keeps all loaded views in DOM, ensure that the controls found belong to the current view
if (oControl.getId().startsWith(viewId) && (oControl instanceof sap.m.Input || oControl instanceof sap.m.DatePicker)) {
var val = oControl.getValue();
if (!val) {
oControl.setValueState(sap.ui.core.ValueState.Error);
oControl.openValueStateMessage();
bError = true;
return false;
} else {
oControl.setValueState(sap.ui.core.ValueState.None);
oControl.closeValueStateMessage();
}
}
});
HTH,
Anton

Brightscript : Web Accordion effect

Right Now I'm creating An application. Here we have Help sections. Usually, Giant applications like Youtube,NetFlix and Vimeo are not showing their Help section in their App. But In our Case, We wanted to show the Help portions. So it will have some questions. But From the design,It is the same like Accordion effect.
I know It is very hard to do it. I don't know, how to to get focus if I use simple Labels.
I have tried some different methods.
Method 1 : By using Label one by one. So I can hide and show by using visible property.
Doubt : So how can I get the focus? so If there are 20 questions, How can I set focus?
Method 2 : By using LabelList. So it has autofocus.
Doubt : So how can I hide and show contents by using LabelGroup? I think, there is no visible property.
And finally, I used an Animation.
Please visit this image
For this, I have used Vector2DFieldInterpolator Animation
And Here is my Code.
<component name = "AnimationV2DExample" extends = "Group" >
<children>
<Rectangle
width = "900"
height = "330"
color = "0x10101000" >
<Label
id="QuestionLabel"
text="What is this?"/>
<Rectangle
id="answer1rect"
width = "900"
height = "330"
color = "0x10101000" >
<Label
id="AnswerLabel"
text="This is a Roku App."
visible="false"/>
</Rectangle>
<Label
id="QuestionLabel1"
text="What is that?"/>
<Rectangle
id="answer2rect"
visible = "false"
color = "0x10101000" >
<Label
id="AnswerLabel"
text="This is a Roku App."
visible="false"/>
</Rectangle>
<Animation
id = "exampleVector2DAnimationrev"
duration = "7"
easeFunction = "outExpo" >
<Vector2DFieldInterpolator
id = "exampleVector2D"
key = "[ 1, 0 ]"
keyValue = "[ [0.0,50.0], [0.0,0.0] ]"
fieldToInterp = "AnswerLabel.translation" />
</Animation>
</Rectangle>
</children>
</component>
And Here is Brightscript
sub init()
examplerect = m.top.boundingRect()
centerx = (1280 - examplerect.width) / 2
centery = (720 - examplerect.height) / 2
m.top.translation = [ centerx, centery ]
m.revanimation = m.top.findNode("exampleVector2DAnimationrev")
m.answer = m.top.findNode("AnswerLabel")
m.answerRec = m.top.findNode("answer1rect")
m.qustion1 = m.top.findNode("QuestionLabel1")
m.qustion1.translation = [40,100]
m.answer.translation = [50,50]
m.question = m.top.findNode("QuestionLabel")
end sub
function onKeyEvent(key as String, press as Boolean) as Boolean
handled = false
if press then
if(key = "OK" AND m.question.id = "QuestionLabel")
m.answer.visible = true
m.revanimation.repeat = false
m.revanimation.control = "start"
handled = true
end if
end if
return handled
end function
So How can I do a successful Accordion with this? Am I going in a right way? Or If it is not possible, Please suggest me the better way.

highlight a changed property on model load

I have a table that where the data is periodically updated by a javascript interval function in my controller:
var model = this.getview().getModel();
var updateModel = setInterval(function(){
model.loadData('path/to/my/data.json');
}, 30000)
This will basically be static display on a public monitor showing a summary of data.
I want to be able to highlight when a property has changed, so I've been trying to add a class to the control when it changes. The class will then highlight this in some way with CSS.
<Table items="{items}">
<columns>
<Column/>
<Column/>
</columns>
<items>
<ColumnListItem>
<cells>
<Text
text="{name}" />
<ObjectStatus
text="{value}"
state="{
path: 'value',
formatter: '.formatter.redOrGreen'
}"/>
</cells>
</ColumnListItem>
</items>
</Table>
So the model updates every 30 seconds. If the {value} field changes, I want to add a class to ObjectStatus control.
At the moment I'm just using a JSON model for local development to see if this is possible, but in production it will be an oData service.
Thanks for the answers, I managed to solve this, but my method wasn't quite covered by the answers on here. This is how I did it:
The requirements for this changed slightly since I posted the question. I'll need to indicate if something has changed, but also if the value has gone up or down. I'll also need to indicate if something goes above or below a certain value. I also wanted to make a solution that could be easily adapted if there are any other future requirements. This will also need to be easily adapted for oData when the backend service is up and running.
First of all (and key to this) is setting up a duplicate model, so this goes into my component.js file .I'm just duplicating the model here so that the values old and new values are unchanged, to make the formatter functions work on the first page load:
var oModel = new JSONModel('/path/to/data.js');
this.setModel(oModel, 'model');
this.setModel(oModel, 'oldModel');
In the controller for my view, I then take a copy of the old data, which goes into the old model that I've attached to the view, the new model is then updated. I do this in the after rendering hook to optimize the initial page load.
onAfterRendering: function(){
var thisView = this.getView();
var updateModel = function(){
var oldData = thisView.getModel('model').getData();
var oldModel = new JSONModel(oldWharehousesData);
thisView.setModel(ollModel, 'oldModel');
//update model
var newModel = thisView.getModel('model');
model.loadData('/path/to/data.js');
};
window.refershInterval = setInterval(updateModel, 30000);
}
I'm then able to input the new and old values to a formatter in my XML view and output a couple of custom data attribute:
<core:CustomData
key="alert-status"
value="{
parts: [
'model>Path/To/My/Property',
'oldModel>Path/To/My/Property'
],
formatter: '.formatter.alertStatus'
}"
writeToDom="true"/>
</customData>
My formatter.js :
alertStatus: function(newValue, oldValue){
var alertNum = 25;
if(newValue < alertNum && oldValue >= alertNum) {
return 'red';
} else if (newValue >= alertNum && oldValue < alertNum) {
return 'green';
} else {
return 'none';
}
}
I can then have as many custom data attributes as I like, run them through their own formatter function, which can be styled to my heart's content, e.g:
compareValues: function(newValue, oldValue) {
if (newValue > oldValue) {
return 'higher';
} else if (newValue < oldValue){
return 'lower';
} else {
return 'false';
}
}
I have build an example on JSBin.
First you have to get the received data. You can use the
Model.attachRequestCompleted event for that:
this.model = new sap.ui.model.json.JSONModel();
this.model.attachRequestCompleted(this.onDataLoaded, this);
In the event handler onDataLoaded you can retrieve the JavaScript object and compare it to a saved copy. You have to write the flags that indicate changes to the array item itself. (Storing it in a separate model as Marc suggested in his comment would not work because in your aggregation binding you only have the one context to your array item.)
At last you have to save the newData object as this.oldData for the next request.
onDataLoaded:function(){
var newData = this.model.getProperty("/");
if (this.oldData){
//diff. You should customize this to your needs.
for(var i = 0, length = Math.min(newData.items.length, this.oldData.items.length); i< length; i++){
newData.items[i].valueChanged = newData.items[i].value !== this.oldData.items[i].value;
newData.items[i].nameChanged = newData.items[i].name !== this.oldData.items[i].name;
}
}
this.oldData = newData;
this.getView().getModel().setProperty("/",newData);
},
You can then bind the ObjectState state property to the flag(s):
<ObjectStatus
text="{value}"
state="{= ${valueChanged} ? 'Warning':'None' }"/>
If you want to change the background color of the whole row or something like that you can apply Bernard's answer and use the flag(s) in a customData attribute.
You can use the <customData> tag
This allows the insertion of a custom attribute into the HTML produced by the XML to HTML conversion process
In the example below for example I add a custom attribute (my own) - this code generates the following attribute data-colour in a relevant HTML element (a <SPAN> tag) - inspect the relevant element using, say, Chrome.
<customData>
<core:CustomData writeToDom="true" key="colour" value="{vproducts>ListCostColour}" />
</customData>
You are then able to create a style for this attribute in your own style sheet as follows (and reference this in your manifest.json)
[data-colour="red"] {
background-color: #ffd1cc;
}
[data-colour="orange"] {
background-color: rgba(255, 243, 184, 0.64);
}
[data-colour="green"] {`enter code here`
background-color: rgba(204, 255, 198, 0.97);
}

How to filter tags in a component dialog. Adobe CQ

I am trying to filter the tags in a component dialog. I know that I can filter it by namespace, however that applies only to root level. Can I filter the tag selection one level deeper?
for example:
etc
tags
namespace
article-type
blog
news
asset-type
image
video
I want to filter the tags in the component dialog so the user can only select the tags under 'article-type'.
Thanks,
Yes and no. Officially you can go deeper according to the widget API, but there is a "bug" in the Widget JavaScript file that prevents it to work. I had the same issue and I just overwrite this JavaScript file.
Widget definition:
<article jcr:primaryType="cq:Widget"
fieldLabel="Article Type"
name="./cq:tags"
tagsBasePath="/etc/tags/namespace"
xtype="tags">
<namespaces jcr:primaryType="cq:WidgetCollection">
<ns1 jcr:primaryType="nt:unstructured" maximum="1" name="article-type" />
</namespaces>
</article>
<asset jcr:primaryType="cq:Widget"
fieldLabel="Asset Type"
name="./cq:tags"
namespaces="[asset-type]"
tagsBasePath="/etc/tags/offering"
xtype="tags"/>
In this case only one Tag below article-type can be selected; you can limit the number with the maximum attribute. The asset-type has no limits. So choose the option that suits your need.
JavaScript overwrite:
To make this work, you need to change the method CQ.tagging.parseTag in /libs/cq/tagging/widgets/source/CQ.tagging.js:
// private - splits tagID into namespace and local (also works for title paths)
CQ.tagging.parseTag = function(tag, isPath) {
var tagInfo = {
namespace: null,
local: tag,
getTagID: function() {
return this.namespace + ":" + this.local;
}
};
var tagParts = tag.split(':');
if (tagParts[0] == 'article-type' || tagParts[0] == 'asset-type') {
var realTag = tagParts[1];
var pos = realTag.indexOf('/');
tagInfo.namespace = realTag.substring(0, pos).trim();
tagInfo.local = realTag.substring(pos + 1).trim();
}
else {
// parse tag pattern: namespace:local
var colonPos = tag.indexOf(isPath ? '/' : ':');
if (colonPos > 0) {
// the first colon ":" delimits a namespace
// don't forget to trim the strings (in case of title paths)
tagInfo.namespace = tag.substring(0, colonPos).trim();
tagInfo.local = tag.substring(colonPos + 1).trim();
}
}
return tagInfo;
};