I have an if block as given below:
if (this.totalTenants === 1) {
this.newTenants.tenant2 = Object.assign({ name: null, number: null }, this.emptyTenant);
this.newTenants.tenant3 = Object.assign({ name: null, number: null }, this.emptyTenant);
this.newTenants.tenant4 = Object.assign({ name: null, number: null }, this.emptyTenant);
this.newTenants.tenant2 = this.emptyTenant;
this.newTenants.tenant3 = this.emptyTenant;
this.newTenants.tenant4 = this.emptyTenant;
this.newTenants.rentAmount = 3200;
}
But when the value of this.totalTenants is 1 it doesn't go into the if block.
I'm working on Angular 6 with typescript.
If I if (this.totalTenants == 1) double equals sign ==
then the if block is executed but I get the error as displayed below:
[tslint] == should be === (triple-equals)
The difference between == and === operators is that the first make an automatic cast to facilitate comparison, the second one does not cast anything.
So if you try to compare two number values, but one of them is a string representation of the number, comparison fails with === operator.
Probably you are using a string value like '1', to check this you can execute something like this:
console.log(typeof this.totalTenants)
If it resulsts in a string you should change your operator to == or cast that value to a number prepending the variable with + like this:
if (+this.totalTenants === 1) {
Related
Right now I am making a currency mask directive that should be compatible with angular reactive forms. Here's my Stackblitz https://stackblitz.com/edit/angular-8-currency-directive-insert.
In the input element, I expect that when I enter 1, then 2, then 3, then 4, then 5 that I would see in the console {currency: "$1,234"} because the mask runs .substring(0,4) however I see {currency: "$1,2345"}.
I see the correct display value of $1,234 within the input element.
If I change .substring(0,4) to .substring(0,3) then the display value within the input element displays $1,23 when I expect it to display $1,234. The console outputs the correct value of {currency: "$1,234"}
Any suggestions that get to the root of the problem are very welcome! I have already done work arounds which involve things like splitting into an array, checking, popping off the end, and joining but those fixes are not ideal. Any suggestions are still welcome though!
Thank you for your support.
The code to focus on is found in currency.directive.ts provided below:
onInputChange(event, backspace) {
let newVal = event.replace(/\D/g, '');
if (newVal.length === 0) {
newVal = '';
} else if (newVal.length <= 3) {
newVal = newVal.replace(/^(\d{0,3})/, '$1');
// } else if (newVal.length <= 4) {
// newVal = newVal.replace(/^(\d{0,1})(\d{0,3})/, '$1,$2');
} else {
newVal = newVal.substring(0, 4);
newVal = newVal.replace(/^(\d{0,1})(\d{1,3})/, '$1,$2');
}
this.ngControl.valueAccessor.writeValue("$"+ newVal);
// console.log(this.toNumber(newVal))
}
Your question inspired me to create a CurrencyDirective that I would use. It does not approach this the way you have but I believe it could be used instead or hopefully to help others.
StackBlitz - Currency Format Directive
Reasons:
We should not be putting currency symbols in our value $1,234
We should format as the user types (painless UX)
We should be saving our currency values as raw numbers (strip
formatting)
We should not be regex'ing for 3 chars, 4 chars, 5 chars etc to conditionally add formatting (commas or dots)
Here's what I did instead.
I handle paste, input and drop events but the formatting is done within getCurrencyFormat():
getCurrencyFormat(val) {
// 1. test for non-number characters and replace/remove them
const filtered = parseInt(String(val).replace(this.currencyChars, ''));
// 2. format the number (add commas)
const usd = this.decimalPipe.transform(filtered, '1.0');
// 3. replace the input value with formatted numbers
this.renderer.setProperty(this.el.nativeElement, 'value', usd);
}
I believe that saving currency should be done in raw numbers. So on form submit I do this:
Number(this.form.get('currency').value.replace(/[^0-9]g/, ''));
Stackblitz https://stackblitz.com/edit/angular-8-currency-directive-insert-jdwx4b
currency custom input
import { Component, forwardRef } from '#angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '#angular/forms';
#Component({
selector: 'app-currency',
template: '<input [(ngModel)]="value" (keyup)="setValue(value)">',
styleUrls: ['./currency.component.scss'],
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CurrencyComponent),
multi: true
}
]
})
export class CurrencyComponent implements ControlValueAccessor {
value;
constructor() {
}
setValue(event) {
let newVal = event.toString().replace(/\D/g, '');
if (newVal.length === 0) {
newVal = '';
} else if (newVal.length <= 3) {
newVal = newVal.replace(/^(\d{0,3})/, '$1');
} else {
newVal = newVal.substring(0, 4);
newVal = newVal.replace(/^(\d{0,1})(\d{1,3})/, '$1,$2');
}
newVal = '$' + newVal;
if (newVal) {
this.value = newVal;
setTimeout(() => {
// sometimes it needs a tick, specially first time
this.propagateChange(this.value);
});
}
}
writeValue(value: any) {
if (value !== undefined) {
this.setValue(value);
}
}
registerOnChange(fn) {
this.propagateChange = fn;
}
registerOnTouched() {
}
propagateChange = (_: any) => {
}
}
usage
<app-currency formControlName="currency"></app-currency>
I am trying to validate a user typed email in Xamarin.Forms with Regex. For that I require that the pattern includes:
var emailPattern = #"^(?("")("".+?(?<!\\)""#)|(([0-9a-z]((\.(?!\.))|[-!#\$%&'\*\+/=\?\^`\{\}\|~\w])*)(?<=[0-9a-z])#))" +
#"(?(\[)(\[(\d{1,3}\.){3}\d{1,3}\])|(([0-9a-z][-\w]*[0-9a-z]*\.)+[a-z0-9][\-a-z0-9]{0,22}[a-z0-9]))$";
Then I match the typed email with the pattern:
if (!Regex.IsMatch(Email, emailPattern) || Email == null)
{
EmailIsWrong = true;
}
else{
EmailIsWrong = false;
}
However, an error occurs, which is System.ArgumentNullException: Value cannot be null.
Parameter name: input on my if statement. I tried fixing it by having Email == null. This error occurs whenever I let the entry be empty.
For your problem, change the order of operands may help.
Like:
if (Email == null || !Regex.IsMatch(Email, emailPattern))
{
EmailIsWrong = true;
}
else{
EmailIsWrong = false;
}
If the first operand is satisfied, the second operand will be skipped
I am currently having a list of obeject defined as:
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
... code below
}
the Tool data class is defined as:
data class Tool(
var id: String = ""
var description: String = ""
var assignedTo: String = ""
)
the Updated data class is defined as:
data class Updated(
var id: String = ""
var assignedTo: String = ""
)
Basically, I parse the list updateTools and if I found a id match in tools, I update the assignedTo field from the Tool type object from tools by the one from updateTools
fun updateList(tools: List<Tool>, updateTools: List<Updated>){
updateTools.forEach{
val idToSearch = it.id
val nameToReplace = it.name
tools.find(){
if(it.id == idToSearch){it.name=nameToReplace}
}
}
return tools
}
it's not working but I do not see how to make it easier to work. I just started kotlin and I feel that it's not the good way to do it
any idea ?
Thanks
First of all:
you're not assigning assignedTo, you're assigning name...
in the predicate passed to find, which
should only return a Boolean value to filter elements, and
should probably not have any side effects,
those should be done later with a call to i.e. forEach.
Additionally, your constructor parameters to the data class are normal parameters, and as such, need commas between them!
Your last code block, corrected, would be:
updateTools.forEach {
val idToSearch = it.id
val nameToReplace = it.name
tools.find { it.id == idToSearch }.forEach { it.assignedTo = nameToReplace }
}
return tools
I'd do it like this (shorter):
updateTools.forEach { u -> tools.filter { it.id == u.id }.forEach { it.assignedTo = u.name } }
This loops through each update, filters tools for tools with the right ID, and sets the name of each of these tools.
I use forEach as filter returns a List<Tool>.
If you can guarantee that id is unique, you can do it like this instead:
updateTools.forEach { u -> tools.find { it.id == u.id }?.assignedTo = u.name }
firstOrNull returns the first element matching the condition, or null if there is none. Edit: it seems find is firstOrNull - its implementation just calls firstOrNull.
The ?. safe call operator returns null if the left operand is null, otherwise, it calls the method.
For = and other operators which return Unit (i.e. void, nothing), using the safe call operator simply does nothing if the left operand is null.
If we combine these, it effectively sets the name of the first element which matches this condition.
First, you're missing comma after properties in your data classes, so it should be:
data class Tool(
var id: String = "",
var description: String = "",
var assignedTo: String = ""
)
data class Updated(
var id: String = "",
var assignedTo: String = ""
)
As for second problem, there're probably number of ways to do that, but I've only corrected your idea:
fun updateList(tools: List<Tool>, updateTools: List<Updated>): List<Tool> {
updateTools.forEach{ ut ->
tools.find { it.id == ut.id }?.assignedTo = ut.assignedTo
}
return tools
}
Instead of assigning values to variables, you can name parameter for forEach and use it in rest of the loop.
I am making a function that takes in an example and an ip address. For ex.
compare('192.168.*','192.168.0.42');
The asterix indicates that the following parts of ip can be anything. The function returns true or false based on if the example and ip is a match. I tried this kind of solution.
var compare = function(example, ip){
var ex = example.split(".");
var ip = ip.split(".");
var t = 0;
for(var i=0; i<4; i++){
if(ex[i] == ip[i] || ex[i] == "*" || typeof ex[i] === 'undefined' && ex[i-1] == "*"){
t++
if(t==4){
return true
}
}else{
return false;
}
}
}
What are the main advantages of using regular expression over this solution? What would be the best regular expression to do this?
How about checking if they are not equal then just return false?
var compare = function(example, ip){
// You should have some basic IP validations here for both example and ip.
var ex = example.split(".");
var ip = ip.split(".");
for(var i=0; i<ex.length; i++){
if(ex[i]=='*')
break;
if(ex[i]!=ip[i])
return false;
}
return true;
}
alert(compare('333.321.*','333.321.345.765'));
alert(compare('333.322.*','333.321.345.765'));
alert(compare('333.321.345.*','333.321.345.765'));
This goes way better with regular expressions. Try this:
function compare(example, ip) {
var regexp = new RegExp('^' + example.replace(/\./g, '\\.').replace(/\*/g, '.*'));
return regexp.test(ip);
}
compare('192.168.*', '192.168.0.42'); // => true
compare('192.167.*', '192.168.0.42'); // => false
What this does is, it translates your pattern to an regular expression. Regular expressions are extremely powerful in matching string. It also covers cases like this:
compare('192.168.*.42', '192.168.1.42'); // => true
compare('192.167.*.42', '192.168.1.43'); // => false
function isEmpty(obj) {
return isNone(obj) || (obj.length === 0 && typeof obj !== 'function') || (typeof obj === 'object' && get(obj, 'length') === 0);
}
1) For null and undefined, we have isNone() function
2) For [], '', we have the second check.
3) The purpose of third check?
I believe that is to check for empty objects that have length as an Ember computed property. IE8 and below has no support for Javascript computed properties, so you have to use the Ember syntax to compute them.