HTML placeholder override the ng-model value if it is 0 - javascript

Is there a way to tell ng-model if your value is 0 then show the placeholder value not the ng-model value.
The reason for this is I have an issue where the UX requires the ng-model to be one value while the business logic requires it to be another.
Something like this.
Controller
$scope.qty = 0;
//...some calculation that requires $scope.qty to be a number
HTML
<input ng-model="qty" placeholder="N/A">
<!-- This will show 0 not N/A as qty has a value-->
I do understand you can edit the functionality of ng-model with the following.
ng-model-options={getterSetter: true}
This does solve this issue in a single ng-model like above but what about when the qty is in a ng-repeat?
In the real world we are making a page that auto calculates the amount of items a user should order based on there inventory. If the inventory is 0 the placeholder is used if it is changed by the user then the value they entered in is used.
As there is more then one product they can order we have this in an ng-repeat.
Controller
$scope.products = [{
//...product data
inventory : 0
}]
HTML
<tr ng-repeat="product in products track by $index">
<td>
<input ng-model="product.inventory" placeholder="N/A">
</td>
</tr>
You can try the setter getter method but as the only value you get is the value entered into the input box you lose the context of which item the user is referring to unless you create a setter getter function for each product.

Try this. You can define a getter function for ng-model directive if you use ng-model-options by setting getterSetter as true. ng-model-options is used to modify the behaviour of ng-model.
<input ng-model="getterSetter" placeholder="N/A" ng-model-options={getterSetter: true}>
// Controller function
$scope.getterSetter = function(value) {
if(value == 0) {
return "N/A";
}
else {
return value;
}
}

You can ngModelOptions, Object to tell Angular exactly when to update the Model.
<input ng-model="updateModel" placeholder="some text" ng-model-options={updateModel: true}>
// Controller method
$scope.updateModel= function(value) {
if(value <= 0) {
return "some text";
}
else {
return value;
}
}

Related

Using get and set on a data property object - VueJS

From what I know VueJS has a way to use a getter and setter for their computed properties per this documentation on Computed property.
I have here the vue component where you can see the amount is an object and we have a group of persons from the vuex store.
data() {
return {
form: {
amounts: {},
},
};
},
mounted() {
const persons = this.$store.getters.getPersons()
persons.forEach((person) => {
this.$set(this.form.amounts, person.id, '0.00');
});
},
I made it so I can associate a person to the amount he has paid on the form by linked it using the ID and the payment. This is an example of what this.form.amounts should look like.
{'HKYDUPOK': 0.00},
{'RYYJPUKA': 0.00},
{'KZMUYTAK': 0.00}
Now by default, their values should be 0.00, on the input number field where they entered the amount, by default I applied them to v-model which looks like this:
<div v-for="person in persons">
<input
class="form-control"
v-model="form.amounts[person.id]"
type="number"
step=".01"
min="0"
required>
</input>
</div>
But here is the thing, when you open your code snippet on the browser, you notice that the input number field has the default value of 0.00 which acts as somewhat a placeholder. I wanted to remove the default value of 0.00 on the number input and have it instead to an empty input yet the underlying value of the amounts per person is not null but still 0.00 or 0. This is so that the form is clear of input when the user tries to input values on the input box instead of having to erase and replace 0.00 with an actual value (Hope this is clear). Now there is a possibility that on the total amount, there are at least 1 or more persons with an amount of 0. I wanted to make sure that an empty input number field does not result in null but instead, it's 0. Is this possible?
I tried checking the computed property getter and setter for this to change the default binding yet how do you map the form.amounts to match the amount to its corresponding person? On the Get, if the value is not more than 0.00 or 0, then return an empty value to the input field. Set is the bigger problem for it only accepts one parameter which is called newValue and would be hard to say pass the personId to map the amounts to the corresponding person. Is there a way to touch upon and manipulate the binding of a data property which is an object yet also change the default behavior on the model to return empty instead of 0.00? I hope my question is clear enough.
I assume this is a follow on from your previous question...
At this stage, you're best creating a component to represent your data input element.
Something like this (using a single-file component example)
<!-- number-input.vue -->
<template>
<input class="form-control" type="number"
step=".01" min="0"
:value="amount"
#input="updated"
required />
</template>
<script>
export default {
name: 'NumberInput',
props: {
value: Number
},
computed: {
amount () {
return this.value || ''
}
},
methods: {
updated ($event) {
this.$emit('input', parseFloat($event.target.value) || 0)
}
}
}
</script>
Then you can use it in your parent template
<div v-for="person in persons" :key="person.id">
<NumberInput v-model="form.amounts[person.id]" />
</div>
Just remember to import and use the component...
<script>
import NumberInput from 'number-input'
export default {
components: { NumberInput },
// etc
}
</script>
JSFiddle Demo
Also see https://v2.vuejs.org/v2/guide/components.html#Using-v-model-on-Components

Boolean filter with checkbox on AngularJS

I have an array of objects with property published which can be true or false.
I'm building a filter to be able to display only published or only not published items.
So far the published one works fine like this:
<input
type="checkbox"
ng-model="search.published"
ng-change="search.published = search.published ? true : undefined">
Published
And in the ng-repeat it looks like this:
ng-repeat="exhibitor in filterItems = (data | filter: search)"
The problem comes when I try to add another checkbox to display only unpublished items.
I've tried this with a second checkbox:
<input
type="checkbox"
ng-model="search.published"
ng-change="search.published = search.published ? false : undefined">
Unpublished
But of course it can't have the same model as the published items one. Also, the checkbox won't get ticked even if I remove the first checkbox.
Any tips on how to work around this?
Checkboxes automatically assign a true or false value to their ng-model values, so it is unnecessary to use ng-change the way you are.
<input
type="checkbox"
ng-model="search.published">
Published
When checked, search.published will be true. When unchecked, it will be false.
Same goes for the second checkbox, but you should use a different ng-model property.
<input
type="checkbox"
ng-model="search.unpublished">
Unpublished
Next you will need to create a custom filter in your controller:
$scope.myCustomFilter = function(exhibitor) {
if (exhibitor.published && exhibitor.published === $scope.search.published) {
return exhibitor;
} else if (!exhibitor.published && exhibitor.published === $scope.search.unpublished) {
return exhibitor;
}
};
You will need you make sure you define $scope.search in your controller.
$scope.search = {
published: false,
unpublished: false
};
Now for your ng-repeat:
ng-repeat="exhibitor in filterItems | filter:myCustomFilter"

Changing ng-model value when using ng-repeat and $index

I have a set of divs, inside a ng-repeat. When I use a ng-model for these, they are all updating when I change the value of this model from a function in the controller. i.e., If I change the model, all the divs are reflecting the same value.
Html:
<tbody ng-repeat="aw in aws">
<div ng-model="currentValue" ng-init="initializeSelects(aw.id)">{{currentValue}}</div>
Controller code:
$scope.initializeSelects = function(awId)
{
$scope.currentValue = "read";
}
I tried changing my code to:
<tbody ng-repeat="(i, aw) in aws track by $index">
<div ng-model="currentValue[i]" ng-init="initializeSelects(aw.id, i)">{{currentValue[i]}}</div>
and
$scope.initializeSelects = function(awId, i)
{
$scope.currentValue[i] = "read";
}
In this case, currentValue always is undefined and the model value can not be changed. Why would it be undefined?
Any inputs would be helpful, thanks in advance!

trying to achieve two way binding between ng-repeate and a form

Values of selected row in ng-repeate get populated in a form below it. to accomplish this i am doing a simple thing
<p ng-repeat="item in array" ng-click="SetCurrVariable(item)">
{{item.ThresholdSet}}
</p>
in the controller i have a function
$scope.array = [
{ ThresholdSet: false },
{ ThresholdSet: false },
{ ThresholdSet: false }
];
$scope.SetCurrVariable = function (variable) {
$scope.CurrVariable = variable;
};
form have a check-box that i bind to a property of CurrVariable
<input id="chkThr" type="checkbox" ng-model="CurrVariable.ThresholdSet">
i am trying to achieve this behavior that if i click the check-Box in the form. The change gets visible in ng-repeate like a two way binding.
Plunkr setup
Updated with $scope
$scope.SetCurrVariable = function (variable) {
$scope.CurrVariable = variable;
};
Use this code in your controller, then the two-way binding should work

Updating a value in an array using a function - Angular JS

I'm relatively new to AngularJS and I've found myself slightly confused.
Here is my controller:
app.controller("calcController", function($scope) {
$scope.interests=[{time:'month',amount:0},
{time:'quarter',amount:0},
{time:'year',amount:0}];
$scope.rates=[{rate:0.01,lower:0,upper:1000,desc:'£0 - £1000'},
{rate:0.02,lower:1000,upper:5000,desc:'£1000 - £5000'},
{rate:0.03,lower:5000,upper:'none',desc:'£5000+'},];
$scope.balance=0;
$scope.updatedIntAmount=function(balance){
if(balance<0){
return 0;
}
else if(balance>=rates[1].lower && balance<rates[1].upper){
return balance*rates[1].rate;
}
else if(balance>=rates[2].lower && balance<rates[2].upper){
return balance*rates[2].rate;
}
else {
return balance*rates[3].rate;
}
}
});
What I want is some way to bind the value of interests.amount to updatedIntAmount.
Here's my HTML:
<div ng-controller="calcController" class="container">
<div class="form-group">
<label for="balInput">Balance:</label>
<input id="balInput" type="text" class="form-control" ng-model="balance">
</div>
<p ng-repeat="interest in interests">{{'per '+interest.time+':'+interest.amount}}</p>
</div>
So what I have is interests.amount dependent on calculateIntAmount, which in turn is dependent on both rates.rate and balance. How can I get these interests.amount values to change whenever balance is updated?
Thanks
Try adding ng-change to your input field like so <input id="balInput" type="text" class="form-control" ng-model="balance" ng-change="updatedIntAmount(balance)">. This will allow you to call the function on a change to the input field and thus do whatever you want within the function in your controller.
You can learn more at the official AngularJS documentation page
You can look into using $scope.$watch to observe any changes in your balance variable, and then update your interests.amount accordingly.
In your controller, you would have:
$scope.$watch('balance', function(newBalance) {
$scope.interests.amount = $scope.updatedIntAmount(newBalance);
});
Lot of errors are present in your code.
as first there is nothing like rates[1] instead you should change it to $scope.rates[1].
Second : your updatedIntAmount function contains rates[3] which is again wrong as you have rates[2] as max limit according to array index rule.
Your updatedIntAmount function return a single value based upon the balance is inserted. in that case after correcting the errors just add :
{{updatedIntAmount(balance)}}
in your html code. it will change as soon as change in balance.
$scope.updatedIntAmount=function(balance){
if(balance<0){
return 0;
}
else if(balance>=$scope.rates[0].lower && balance<$scope.rates[0].upper){
return balance*$scope.rates[0].rate;
}
else if(balance>=$scope.rates[1].lower && balance<$scope.rates[1].upper){
return balance*$scope.rates[1].rate;
}
else {
return balance*$scope.rates[2].rate;
}
}

Categories

Resources