Vue.Js comparing string failed - vue.js

I'm new to vue.js. I've tried this way to compare two strings, but it seems to fail in vue. How can I solve this issue?
I've tried this:
app.vue
#Component
export default class Game extends Vue{
public word = ""
public words: Array<string> = ["hello", "world"]
public checkValue(): void{
const firstWord = this.words.shift();
if(firstWord === this.word){ // this condition is failing
console.log("Success")
}
}
}
app.html
<md-input v-on:keyup.space="checkValue()" v-model="word"></md-input>
Why this condition is failing?

Because you have an event keyup with space so word always have a space at end. Please trim before compare.
#Component
export default class Game extends Vue{
public word = ""
public words: Array<string> = ["hello", "world"]
public checkValue(): void{
const firstWord = this.words.shift();
if(firstWord === this.word.trim()) {
console.log("Success")
}
}
}

change the below block of code, it should solve your issue
if (firstWord === this.word.trim()) {
// to do
console.log("Success");
}
actually this.word always containing a space with your given word into input box. thats why it will never match. so you have to trim the given input word.
you can check the result

Related

mobx challenge: getters and setters into an observable array

I'm trying to write getters and setters into an observable array and it isn't working. The code below gives me the following error: Error: [MobX] No annotations were passed to makeObservable, but no decorator members have been found either
I've tried different combinations of decorators, but nothing seems to work. The behavior I want is whenever AppModel.text is updated, any UI rending the getter for text should update. Also whenever gonext() is called on the object, then any UI rending from AppModel.text should update and render data from the new 0 item on the array.
class DataThing
{
#observable text?: string = "foo";
}
class AppModel
{
get text() { return this.items[0].text}
set text(value: string | undefined) { this.items[0].text = value;}
items: DataThing[] = observable( new Array<DataThing>());
constructor() {
makeObservable(this);
this.items.push(new DataThing());
}
gonext() { this.items.unshift(new DataThing()); }
}
EDIT:
I ended up doing the following, but would still like to understand how to index into an array in an observable way.
class DataThing
{
#observable text?: string = "zorp";
constructor(){makeObservable(this);}
}
class AppModel
{
#observable _current?:DataThing;
get current() {return this._current;}
items: DataThing[] = observable( new Array<DataThing>());
constructor() {
makeObservable(this);
this.gonext();
}
gonext() {
this.items.unshift(new DataThing());
this._current = this.items[0];
}
}

Adding lit-element and lit-html to a global variabel

I have several lit-elements on my page, but I can't compile them all together so I would like to "share" the lit stuff through a global variable. Might be a bit unconventional, but right now it will save me a lot of bytes.
I'm using rollup to do the packaging.
I think I'm pretty close to achieve what I want, but there is something that I'm missing...
This is my component..
#customElement('tab-strip')
export class TabStrip extends LitElement {
Resulting in
var tabstrip = (function (exports, litElement, repeat, classMap) {
//SOME OTHER STUFF
exports.TabStrip = class TabStrip extends litElement.LitElement {...
.
.
.
${repeat.repeat(this._tabs, e => litElement.html
}({}, Globals, Globals.repeat, Globals.classMap))
I have create a Globals.ts file that looks like this..
import { customElement, html, LitElement, property } from "lit-element";
import { Template, TemplateResult } from "lit-html";
import { classMap } from "lit-html/directives/class-map";
import { repeat } from "lit-html/directives/repeat";
class Globals {
public html = html;
public LitElement = LitElement;
public customElement = customElement;
public property = property;
public repeat = repeat;
public classMap = classMap;
public Template = Template;
public TemplateResult = TemplateResult;
}
window["Globals"] = new Globals();
And at last my rollup.config
input: inputDir + name + ".ts",
output: {
file: outputDir + name + ".js",
name: name,
format: format,
sourcemap: true,
globals: {
"lit-element": "Globals",
'customElement': 'Globals.customElement',
'lit-html': "Globals.LitHtml",
'html': "Globals.html",
'property': "Globals.property",
'lit-html/directives/repeat': "Globals.repeat",
'lit-html/directives/class-map': 'Globals.classMap',
'Template': 'Globals.Template',
'TemplateResult': 'Globals.TemplateResult'
}
},
plugins: [
typescript({
experimentalDecorators: true
}),
resolve(),
// terser({"ecma":"2019"}),
],
external: ['lit-element', 'lit-html', "lit-html/directives/repeat", "lit-html/directives/class-map"]
Gut feeling is that I have misunderstood something in the external stuff of rollup..
AS you can see in the generated file it says litElement.LitElement instead of just litElement
Any help??
Does it work for you? This seems correct just taking it at face value.
Looking at what your Globals is, it's an object with the properties LitElement, property, html, and so on.
If we look at your tabstrip function, the second argument is litElement, which matches the Globals Object being passed in.
So class TabStrip extends litElement.LitElement
makes sense, since the litElement is referencing your Globals object, and that has the LitElement property.

How to write a custom ValidationRule

The intro for the aurelia-validation plugin contains a section on creating custom ValidationRules, by extending the ValidationRule class and passing it to the passes function. The example given is as follows:
import {ValidationRule} from './plugins/validation/';
export class MyValidationRule extends ValidationRule{
constructor (isValid) {
super(
isValid, //pass any object as 'threshold'
(newValue, threshold) => { //pass a validation function
return threshold;
}
(newValue, threshold) => { //Optionally pass a function that will provide an error message
return `needs to be at least ${threshold} characters long`;
},
);
}
}
What do I do with this? For example, for demo purposes if i wanted to make a function that checks if the value is a phone number with regex, how would i code that using this template? I'm asking because the documentation is sparse with examples; there are none for writing custom validation rules and the other example shows how to add one to the ValidationGroup prototype but I would like to know both methods of adding a custom rule
First, you don't have to create a custom validation rule class. You may just make a function which accepts an argument and returns the validation result, e.g.
function validatePhoneNumber(newValue) {
return true/*your RegExp check should return true/false here*/;
}
and then
this.validation = validation.on(this)
.passes(validatePhoneNumber);
If you think you need a class to make validation more generic, try something like
import {ValidationRule} from './plugins/validation/';
export class RegExpValidationRule extends ValidationRule {
constructor (regExp, errorMessage) {
super(
regExp,
(newValue, threshold) => {
return true/*your RegExp check should return true/false here*/;
},
(newValue, threshold) => {
return errorMessage;
}
);
}
}
and then
var validationRule = new RegExpValidationRule(/*your RegExp*/, 'Invalid phone number');
this.validation = validation.on(this)
.passesRule(validationRule);

Custom format functions for StringTemplate4

I would like to know how to create a custom format function for string template. Let say I have the following code:
render(attributes) :: <<
<html>
$atributes: {
<div> $customformat(atribute.name)$</div>
}
</html>
>>
customformat(name) ::= <<
$name; format="upper"$
>>
Currently the behaviour of the function customformat is:
Input: "hello world" -> Output: "HELLO WORLD"
And I would like to modify the customformat function so the output is something like the following:
Input: "hello world" -> Output: "HELLO_WORLD"
As far as I'm aware this isn't possible, since StringTemplate is all about strict model-view separation.
Instead, I think you'd be better off having a getter in the controller that returned the formatted string.
You might find this question useful: embed java code inside a template
Actually, I found a simple way of doing this which avoids the need for the formatted string getters:
You need to create a new StringRenderer which can format the string in the way you want.
public class MyStringRenderer extends StringRenderer
{
#Override
public String toString(Object o, String formatString, Locale locale) {
if (!("upperAndUnder".equals(formatString)))
return super.toString(o, formatString, locale);
// we want upper case words with underscores instead of spaces
return ((String) o).replaceAll(" ", "_").toUpperCase(locale);
}
}
Then you'll need to let the template group know about the new renderer:
public static void main(String[] args) {
STGroup templates = new STGroupFile("test.stg");
templates.registerRenderer(String.class, new MyStringRenderer());
ST renderTemplate = templates.getInstanceOf("render");
renderTemplate.add("attributes", new String[]{"blahh blahh I'm a string", "I'm another string"});
System.out.println(renderTemplate.render());
}
Then you can call the format function like you did before, but pass "upperAndUnder" as the parameter:
group test;
delimiters "$","$"
render(attributes) ::= <<
<html>
$attributes:{ attribute | <div> $customFormat(attribute)$</div>}; separator="\n"$
</html>
>>
customFormat(name) ::= <<
$name; format="upperAndUnder"$
>>
which prints:
<html>
<div> BLAHH_BLAHH_I'M_A_STRING</div>
<div> I'M_ANOTHER_STRING</div>
</html>
FYI:
Here's the original StringRenderer code
More info on Renderers
Try this one
Object rendering using AttributeRenderer
public class BasicFormatRenderer implements AttributeRenderer {
public String toString(Object o) {
return o.toString();
}
public String toString(Object o, String formatName) {
if (formatName.equals("toUpper")) {
return o.toString().toUpperCase();
} else if (formatName.equals("toLower")) {
return o.toString().toLowerCase();
} else {
throw new IllegalArgumentException("Unsupported format name");
}
}}

Recommended way to restrict input in JavaFX textfield

It may seem the question is the duplicate of this. But my question is i have developed a integer textfield in JavaFX by two ways. The code is given below
public class FXNDigitsField extends TextField
{
private long m_digit;
public FXNDigitsField()
{
super();
}
public FXNDigitsField(long number)
{
super();
this.m_digit = number;
onInitialization();
}
private void onInitialization()
{
setText(Long.toString(this.m_digit));
}
#Override
public void replaceText(int startIndex, int endIndex, String text)
{
if (text.matches(Constants.DIGITS_PATTERN) || text.equals(Constants.EMPTY_STRING)) {
super.replaceText(startIndex, endIndex, text);
}
}
#Override
public void replaceSelection(String text)
{
if (text.matches(Constants.DIGITS_PATTERN) || text.equals(Constants.EMPTY_STRING)) {
super.replaceSelection(text);
}
}
}
And the second way is by adding an event Filter.
The code snippet is given.
// restrict key input to numerals.
this.addEventFilter(KeyEvent.KEY_TYPED, new EventHandler<KeyEvent>() {
#Override public void handle(KeyEvent keyEvent) {
if (!"0123456789".contains(keyEvent.getCharacter())) {
keyEvent.consume();
}
}
});
My question is which is the slandered way to do this? Can anyone help me to pick up the right?
The best way to add validation in TextField is a 3rd way.
This method lets TextField finish all processing (copy/paste/undo safe).
It does not require you to extend the TextField class.
And it allows you to decide what to do with new text after every change
(to push it to logic, or turn back to previous value, or even to modify it).
// fired by every text property changes
textField.textProperty().addListener(
(observable, oldValue, newValue) -> {
// Your validation rules, anything you like
// (! note 1 !) make sure that empty string (newValue.equals(""))
// or initial text is always valid
// to prevent inifinity cycle
// do whatever you want with newValue
// If newValue is not valid for your rules
((StringProperty)observable).setValue(oldValue);
// (! note 2 !) do not bind textProperty (textProperty().bind(someProperty))
// to anything in your code. TextProperty implementation
// of StringProperty in TextFieldControl
// will throw RuntimeException in this case on setValue(string) call.
// Or catch and handle this exception.
// If you want to change something in text
// When it is valid for you with some changes that can be automated.
// For example change it to upper case
((StringProperty)observable).setValue(newValue.toUpperCase());
}
);
JavaFX has a class TextFormatter for this use-case.
It allows you to validate and adjust the text content before it is "commited" to the textProperty of the TextField.
See this example:
TextFormatter<String> textFormatter = new TextFormatter<>(change -> {
if (!change.isContentChange()) {
return change;
}
String text = change.getControlNewText();
if (isValid(text)) { // your validation logic
return null;
}
return change;
});
textField.setTextFormatter(textFormatter);
In both of your ways, you are not allowed to type characters other then numeric characters. But it will allow to paste any character there (Copy Text from any source and Paste in your TextField).
A good way to do validation is after submitting it,
Like (For integers):
try {
Integer.parseInt(myNumField.getText());
} catch(Exception e) {
System.out.println("Non-numeric character exist");
}
(or you can use any combination of yours + the above method)
Similar of what Manuel Mauky posted, but in groovy is:
Note: This will prevent any other character except for digits to be input.
def digitsOnlyOperator = new UnaryOperator<TextFormatter.Change>() {
#Override
TextFormatter.Change apply(TextFormatter.Change change) {
return !change.contentChange || change.controlNewText.isNumber() ? change : null
}
}
textField.textFormatter = new TextFormatter<>(digitsOnlyOperator)
There is probably a shorter way to do it in groovy. If you know it, please post it here.
This code snippet allows just digits to be entered by the user in a TextField.
/**
* This will check whether the incoming data from the user is valid.
*/
UnaryOperator<TextFormatter.Change> numberValidationFormatter = change -> {
if (change.getText().matches("\\d+")) {
return change; //if change is a number
} else {
change.setText(""); //else make no change
change.setRange( //don't remove any selected text either.
change.getRangeStart(),
change.getRangeStart()
);
return change;
}
};
TextFormatter tf = new TextFormatter(numberValidationFormatter);
textfield.setTextFormatter(tf);