Dynamically changing the glyphicon of input add on - angularjs

How to change **glyphicon" (right side of input field (see below)) on validation of input type ?
eg. When input is valid, change it to glyphicon-ok (tick mark ) or when it is invalid change it to glyphicon-remove ( cross sign )
vm.rentalFields = [
{
key: 'first_name',
type: 'input',
// class:glyphicon-ok,
templateOptions: {
type: 'text',
label: 'First Name',
placeholder: 'Enter your first name',
required: true,
"addonRight": {
"class": "glyphicon glyphicon-ok form-control-feedback"
}
}
}];

With angular-formly, if you want anything to be dynamic, you use expressionProperties. Because you want the class property of addonRight to be dynamic, your expressionProperties property for that will be:
'templateOptions.addonRight.class': '"glyphicon form-control-feedback glyphicon-" + (fc.$valid ? "ok" : "remove")'
The values of expressionProperties are called formly expressions which basically means they can be strings which are evaluated on the formly-field's $scope or a function that is passed ($viewValue, $modelValue, scope) and can return the value or a promise that resolves to the value.
The fc you see in that expression is a shortcut for options.formControl which is assigned to your field's NgModelController (which is why you have access to $valid.
At the end of the day, your field config will look something like this:
vm.rentalFields = [
{
key: 'first_name',
type: 'input',
templateOptions: {
type: 'text',
label: 'First Name',
placeholder: 'Enter your first name',
required: true,
addonRight: {
class: 'glyphicon glyphicon-ok form-control-feedback' // <-- initialized to a valid state
}
},
expressionProperties: {
'templateOptions.addonRight.class': '"glyphicon form-control-feedback glyphicon-" + (fc.$valid ? "ok" : "remove")'
}
}
];

You need to add ng-class on the container that stores the glyphicon, and then conditional check a variable that stores the validity of the input. For example this is the approach using forms:
<form class="form-inline" name="myForm">
<input type="text" class="form-control" name="firstName" ng-model="firstName" ng-maxlength="5" />
<span class="glyphicon" ng-class="{'glyphicon-ok': myForm.firstName.$valid, 'glyphicon-remove': myForm.firstName.$invalid}"></span>
</form>
Where myForm.firstName.$invalid is the condition on which you set glyphicon.
(Which is set by the ng-maxlength directive on the input, see this: https://docs.angularjs.org/api/ng/directive/input).
Alternatively you can use a separated variable to store the validity of the input based on some rules you figure out in your controller.
See this fiddle: http://jsfiddle.net/HB7LU/14198/

This will work:
<span class="glyphicon green" ng-class="{'glyphicon-ok': {{single_request.status}}==1, 'glyphicon-remove': {{single_request.status}}==0 }" ></span>

Related

How to use Vuelidate for an Object of an Array?

I have the following vue array;
server: [
{ id: 1, name: 'Name A', ipaddress: '192.168.1.1', status: true, applied: true, modal: false },
{ id: 1, name: 'Name A', ipaddress: '192.168.1.1', status: true, applied: true, modal: false },
]
I use this array to show these information on a data table. Users can add new rows to this table, that is, they can push the array. In addition, they can delete the rows they want from the table with the splice method. Finally, each row has an edit button. Since these buttons are connected to the elements in the array with the v-model, users can make changes on the row they want in the modal window that opens.
Adding and editing operations are carried out with two different modalities that open when the button is pressed.
In line with all this information, there is a question I want to ask. How can I write validation with Vuelidation to an array where new rpws can be added continuously? Here is my vuelidation functions;
validations: {
server: {
required,
$each: {
name: {
required
},
ipaddress: {
required
}
}
}
}
As an example, I just defined the required attribute for two elements. And here is how I use them in my add and edit modals;
<div>
<div">
<label>Name</label>
</div>
<div>
<label>:</label>
</div>
<div>
<input v-if="server[i].modal" v-model="server[i].name" type="text"/>
</div>
<small class="error-msg" v-if="!$v.server[i].name.required && $v.server[i].name.$dirty">Name is required.</small>
</div>
Here is how I add a new row to the table;
addNewRow(){
this.server.push({
name: "",
ipaddress: "",
status: true,
applied: false,
modal: false
});
},
And now I have this error;
[Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"
I think I'm missing an important part here so how can I make this correct? Thanks in advance.
Your add modal might be delay with the template so no server[i] item would be defined. I would suggest using a different variable for add (newItem = {name: '', ...})

How do I set the value of a checkbox with mobx-form?

Using mobx-form I'm trying to set mark a checkbox to checked when the form loads. Setting the value or checked properties doesn't seem to work.
const fields = [
{
name: 'my_checkbox',
label: 'The Checkbox: ',
type: 'checkbox',
rules: 'boolean',
value: true, // do I set initial, default ?
checked:true
},
];
...
<input {...form.$('my_checkbox').bind()} />
Full sample code https://codesandbox.io/s/N914WNRpv
You can pass a checked property like this
<input
checked={field.value}
{...field.bind({
type: 'checkbox',
})}
/> {field.label}
See: https://github.com/foxhound87/mobx-react-form-demo/blob/master/src/components/inputs/SimpleCheckbox.jsx
The checked={field.value} must be after the "bind" function, if you want the default value working properly !!
<input
{...field.bind({
type: 'checkbox',
})}
checked={field.value}
/> {field.label}

VUEjs templates multiple selectboxes

So, I'm assigned to work with vue at work, but VUE and I aren't friends yet. Currently I'm facing an issue that I don't know how to resolve - I'll explain it the best I can with the limited VUE knowledge I possess.
Simplistically I have a vue component, which looks like this:
Vue.component('input-checkboxes', {
template: '#input_checkboxes',
props: ['id', 'label', 'list', 'required', 'readonly']
});
Then I have a template that looks like this:
<template id="input_checkboxes">
<div>
<div>{{ label }}</div>
<div>
<label v-for="list_item in list">
<input type="checkbox" v-model="value" :name="id" :required="required" :readonly="readonly" value="{{ list_item.name }}"> {{ list_item.name }}
</label>
</div>
</div>
</template>
Then I have a rather large vue instance that I'll paste the relevant parts of here.
This variable is being created:
var some_form = {
form : {
Endless: '',
Amounts: '',
Of: '',
Names: '',
In: '',
The: '',
Form: '',
THIS-ONE: ''
}
};
var vm = new Vue({
el: '#form_product',
data: $.extend({
someStuff : 'some values',
someLists : {}
}, some_form),
ready: function() {
this.getLists(); // Fetches alot of lists
},
methods: {
this.$http.get(
framework.url('api','getLookupLists')
).then(function (response) {
this.lists = response.body;
this.pageLoading = false;
}.bind(this));
}
In the end I have my html page that amongst loads of other fields, that works very well, has this:
<input-checkboxes
id="THIS-ONE"
label="A Fitting Label"
:value.sync="form.SomeID"
:list="lists.AnAppropriateList">
</input-checkboxes>
So, that's the gist of the setup. I have numerous other components like input-text, that works just fine (someone else made it before I did), I even created other components by copying his way, and just changing some elements.
I cannot get checkboxes to work, I think my problem is that there are numerous inputs, and that I don't know how to bind the results of those inputs to my VUE instance.
I really hope this makes sense, because I would really like some pointers on how to get on... Maybe if someone duplicated this setup really simplistic and showed how the array of values from the checkboxes could be bound to the vue instance?
There are a couple of mistakes you are (or might be) making.
First of all, the value prop you pass down has to be an array (seems
like it's a string from your example)
value is not correctly set, you need to set it by doing :value="someValue"; you can't have curlies in an attribute.
Lastly, value should probably be the id of the item and not the name. You have a chance of a collision if you use the name.
Bonus: you don't need to use :name at all (unless you are submitting the form server side...? But I can't see why you would do that.)
Here's a simple working example to sum this up:
HTML
<label v-for="list_item in list">
<input type="checkbox" v-model="value" :required="required" :readonly="readonly" :value="list_item.id"> {{ list_item.name }}
</label>
JS
var app = new Vue({
el: 'main',
data: function () {
return {
value: [],
label: 'Label name',
readonly: false,
required: true,
list: [
{
name: 'Item 1',
id: 'item1'
},
{
name: 'Item 2',
id: 'item2'
}
]
}
}
})
I've also made a bin for you to try it out.

Angular Formly - Highlight field based on custom validation

Currently, I have a formly field set up as such:
{
key: 'id',
type: 'input',
validators: {
validId: function($viewValue, $modelValue, scope){
var value = $modelValue || $viewValue;
if(value){
return isAlphanumeric(value);
}else{
return false;
}
}
},
templateOptions: {
label: 'ID',
options: [],
required: true
}
},
isAlphanumeric() is a function I wrote that determines if a string is alphanumeric--this works as intended. However, the user is still allowed to Submit the form (which obviously does not work, as it will produce en error).
How might I go about highlighting the field red (as if it were a required field that was not filled in) if the contents are not valid, preventing the user from submitting until they enter a valid value?
You can use ngClass and assign css classes based off of an expresion. for example (taken straight from their page)
<p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
implemented with your code
<p ng-class="{strike: validId(1,2,yourscope), bold: important, 'has-error': error}">Map Syntax Example</p>

AngularJS: Binding boolean value to radio button such that it updates model to false on uncheck event

In my AngularJS application, I am displaying contacts data in a grid. My typical contacts JSON looks like as below ...
[
{ type: "IM", value: "mavaze123", default: true },
{ type: "IM", value: "mvaze2014", default: false },
{ type: "IM", value: "mavaze923", default: false },
{ type: "IM", value: "mvaze8927", default: false },
{ type: "Email", value: "mavaze123#abc.com", default: true },
{ type: "Email", value: "mvaze2014#xyz.net", default: false }
]
The last property 'default' is actually a radio button, selection of which should alter the original default value of the corresponding contact type in above JSON. There can be one default from each type of contact i.e. we can group radio buttons based on the contact type.
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true"/></div>
</div>
Note: The above code is not the exact one, but approximately same, as
it will appear inside a custom grid component.
Now when I load my view/edit form page with above JSON, it correctly shows the radio state of all contacts. The problem comes, after page load, when user selects another contact as default. This actually changes the model value of default to true for newly selected contact however the model value of original default contact still remains true, even though its radio state changes to uncheck/blur (because they are having same 'name' value).
I thought to write a directive, but I am unable get it triggered on radio on-blur/uncheck event.
There are various posts on binding boolean values to radio buttons, but I am unable to get it work in my scenario, as I want to update model values for individual radio button in a radio group. See there is no single model representing a radio group.
I think you should change your design to separate the contacts from contactTypes and store the key to the default contact in contact type.
In your current design, there are duplicated values for default and that's not the desired way to work with radio.
$scope.contacts = [
{ type: "IM", value: "mavaze123" },
{ type: "IM", value: "mvaze2014" },
{ type: "IM", value: "mavaze923" },
{ type: "IM", value: "mvaze8927" },
{ type: "Email", value: "mavaze123#abc.com" },
{ type: "Email", value: "mvaze2014#xyz.net" }
];
$scope.contactTypes = {
"IM": { default:"mavaze123"}, //the default is contact with value = mavaze123
"Email": { default:"mavaze123#abc.com"}
};
You Html:
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contactTypes[contact.type].default" ng-value="contact.value"/></div>
</div>
DEMO
I assume that the key of contact is value, you could use an Id for your contact.
I added an attribute directive in my input statement ...
<div ng-repeat="contact in contacts">
<div>{{contact.type}}</div>
<div>{{contact.value}}</div>
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="true" boolean-grid-model /></div>
</div>
And my custom directive ...
myModule.directive('booleanGridModel') {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, controller) {
var radioSelected = scope.$eval(attrs.ngModel);
if(radioSelected) {
var selectedContact = scope.contact;
_.each(scope.contacts, function(contact) {
if(contact.type === selectedContact.type) {
_.isEqual(contact, selectedContact) ? contact.default = true : contact.default = false;
}
});
}
}
};
}
WHy you declare ng-value="true" please remove that
<div><input type="radio" name="{{contact.type}}" ng-model="contact.default" ng-value="{{contact.default}}"/></div>
Please use $scope.$apply() in your value changing code
Like something below
$scope.$apply(function ChangeType()
{
/Code
});
And you need to change name="{{contact.type}}" to name="contact.type{{$index}}" Because some types are same name.

Resources