Add Required to Angular Directive - javascript

I have the following Angular directive:
app.directive('basicInput', function () {
return {
restrict: 'AE',
templateUrl: 'DirectiveTemplates/BasicInput.html',
replace: true,
scope: {
ngModel: '=',
visual: '#',
placeholder: '#',
pattern: '=',
ngChange: '='
}
};
});
With the following Template:
<ng-form name="basicInput">
<div class="form-group">
<label for="input">{{visual}}</label>
<input type="text" class="form-control" name="input" ng-model="ngModel" placeholder="{{placeholder}}" required ng-pattern="pattern">
<div ng-messages="basicInput.input.$error" class="help-block">
<span ng-message="required"> Required</span>
<span ng-message="pattern"> Invalid Characters or is too short</span>
</div>
</div>
</ng-form>
Which I call in html as (for example):
<basic-input ng-model="formData.official_name" data-visual="Official Name" data-placeholder="Name" pattern="regex.short"></basic-input>
My Question is, how can I make the 'required' on the input tag from the template optional?

Try this:
Directive:
scope: {
ngModel: '=',
visual: '#',
placeholder: '#',
pattern: '=',
ngChange: '=',
isRequired: '='
}
Template:
<input type="text" class="form-control" ng-required="isRequired" name="input" ng-model="ngModel" placeholder="{{placeholder}}" ng-pattern="pattern">
Usage:
<basic-input ng-model="formData.official_name" is-required="false" data-visual="Official Name" data-placeholder="Name" pattern="regex.short"></basic-input>

ngRequired
you can set ng-required attribute to true or false ,, according to an attribute
docs : https://docs.angularjs.org/api/ng/directive/input

Related

Radio buttons inside directive in a ng-repeat not working in AngularJS

I have a set of radio buttons inside a directive. The directive has an ng-repeat, so it exists multiple times.
I'm able to populate the input fields of the directive, but the radio buttons won't react.
angular.module('account-form-client-de', [])
.controller('ctrl', function($scope) {
$scope.owners = [];
$scope.addOwner = function() {
$scope.owners.push({
class: 'person',
name: 'new owner',
percentage: 0
});
}
$scope.addOwner();
$scope.addOwner();
})
.directive("newOwner", function() {
var options = {
restrict: 'E',
replace: true,
scope: {
owner: '=',
remove: '&'
},
link: function(scope, element, attrs, controller, $parent) {
},
template: `
<div class="table-owners item-row">
<div class="checkbox">
<input type="radio" name="type" ng-model="owner.class" value="person" validate-on-change>
<label for="person" translate>
table_owners.person
</label>
</div>
<div class="checkbox">
<input type="radio" name="type" ng-model="owner.class" value="company" validate-on-change>
<label for="company" translate>
table_owners.company
</label>
</div>
<input name="owners_name" ng-model="owner.name" type="text" placeholder="" class="form-control input-md">
<input name="owners_percentage" ng-model="owner.percentage" type="number" placeholder="" class="form-control input-md">
</div>`
};
return options;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="account-form-client-de" ng-controller="ctrl">
<pre>{{owners}}</pre>
<new-owner ng-repeat="owner in owners track by $index" owner="owner"></new-owner>
<button ng-click="addOwner()">add owner</button>
</div>
Since both the inputs and radio buttons refer to a property in the owner object, I fail to see why the inputs bind, and the radio buttons won't even become checked.
Any ideas?
It's because when you have the same directive multiple times, you have the same radio buttons with the same values multiple times. Then, the HTML parser gets confused. I fixed it by wrapping each row in a <form> (which you don't have to submit), so it's valid again.
angular.module('account-form-client-de', [])
.controller('ctrl', function($scope) {
$scope.owners = [];
$scope.addOwner = function() {
$scope.owners.push({
class: 'person',
name: 'new owner',
percentage: 0
});
}
// Add two owners to begin with
$scope.addOwner();
$scope.addOwner();
})
.directive("newOwner", function() {
var options = {
restrict: 'E',
replace: true,
scope: {
owner: '=',
remove: '&'
},
link: function(scope, element, attrs, controller, $parent) {
},
template: `
<form class="table-owners item-row">
<div class="checkbox">
{{owner.class}}
<input type="radio" name="person" value="person" ng-model="owner.class">
<label for="person" translate>
table_owners.person
</label>
</div>
<div class="checkbox">
<input type="radio" name="company" value="company" ng-model="owner.class">
<label for="company" translate>
table_owners.company
</label>
</div>
<input name="owners_name" ng-model="owner.name" type="text" placeholder="" class="form-control input-md">
<input name="owners_percentage" ng-model="owner.percentage" type="number" placeholder="" class="form-control input-md">
</form>`
};
return options;
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="account-form-client-de" ng-controller="ctrl">
<pre>{{owners}}</pre>
<new-owner ng-repeat="owner in owners track by $index" owner="owner"></new-owner>
<button ng-click="addOwner()">add owner</button>
</div>

Show Input Error Using Custom directives Without Using NgMessages

I Have input and I use a custom directive to display the input error with use of ng-messages. And I want to use attribute for showing the error, not ng-message.
Here is my Code
<md-input-container class="md-block" flex-gt-sm>
<label>Enter Your Message</label>
<input required md-no-asterisk ng-model="newEmployee.message" type="text" id="name" name="name" formValidate>
<div ng-messages="Employeeform.message.$error">
<div ng-message="messageValidator">Message is Invalid
</div>
</md-input-container>
Directive :
app.directive('formValidate', function() {
return {
restrict: 'A',
require: 'ngModel',
template: '<p>Name is required</p>',
link: function(scope, element, attr, ctrl) {
function formValidate(ngModelValue) {
if ([A - z].test(ngModelValue)) {
ctrl.$setValidity('formValidate', false)
} else {
ctrl.$setValidity('formValidate', true),
}
return ngModelValue;
}
ctrl.$parsers.push(formValidate);
}
};
});
Make use of angular-form. Go through this doc https://docs.angularjs.org/guide/forms
Without ng-messages
<div class="form-group" ng-class="{ 'has-error': vm.form.firstname.$touched && vm.form.firstname.$invalid }">
<label class="control-label col-xs-3" for="firstname">First Name</label>
<div class="col-xs-9">
<input class="form-control" name="firstname" id="firstname" ng-model="vm.firstname" type="text" ng-change = "vm.resetValidationErrors('firstname')" required/>
<p ng-show="vm.form.firstname.$error.required && vm.form.firstname.$touched" class="help-block">First name is required.</p>
<p ng-show="vm.form.firstname.$error.firstname && vm.form.firstname.$touched" class="help-block">{{ vm.form.firstname.errorMessage }}</p>
</div>
</div>

Creating a directive with a dynamic ng-options

Okay, so here's my custom directive:
angular.module('bulwarkWebControls', [])
.directive('dropdownList', [
function() {
return {
scope: {
label: '#', // optional
changeCallback: '&',
options: '=',
required: "=",
disabled: "=",
id: "=",
name: "=",
model: "=",
value: "=",
display: "="
},
restrict: 'E',
replace: true, // optional
templateUrl: 'app/templates/dropDownList.html',
link: {
pre: function (scope, element, attr) {
scope.expression = "o."+value +" as o."+display+" for o in options";
}
}
};
}
]);
Template:
<div class="row form-group form-horizontal">
<label data-for="id" class="control-label col-md-3">{{label}}</label>
<div class="col-md-9">
<select data-id="id" data-name="name" data-ng-disabled="disabled" class="form-control"
data-ng-model="model"
data-ng-options="{{expression}}" data-ng-required="required">
<option></option>
</select>
</div>
Html code that utilizes the directive:
<div>
<dropdown-list data-label="Phone(s)" data-id="phoneList" data-name="phoneList"
data-disabled="vm.workOrder.Contacted"
data-model="vm.workOrder.PhoneNumber_Id" data-value="Id" data-display="Number"
data-options="vm.workOrder.CustomerPhoneNumbers" data-required="vm.workOrder.SpokeTo_Id!=5" />
</div>
What I am trying to do is basically create the expression for the ng-options dynamically at run-time based on the "display" and "value" parameters that I am passing to the directive. You can see that in the "pre:" linking function inside the directive. Now, I know that this is not working because at the time this function is being executed I do not have the scope values. However, I cannot do this in the post: linking because that would be too late for the ng-options expression. Is there a way to achieve this functionality or am I totally barking up the wrong tree here? Thank you so much in advance.
Never mind. I used the following code in the template:
<div class="row form-group form-horizontal">
<label data-for="id" class="control-label col-md-3">{{label}}</label>
<div class="col-md-9">
<select data-id="id" data-name="name" data-ng-disabled="disabled" class="form-control"
data-ng-model="model"
data-ng-options="o.{{value}} as o.{{display}} for o in options" data-ng-required="required" compile>
<option></option>
</select>
</div>
That, and I took whatever code I had originally put in the pre: linking function inside the directive.

Field not repeating properly in Angular after combining scopes

I just combined my scopes for models using this method: How can I combine multiple scope models in Angular?
but now it's creating a separate field object outside of the fields object which it didn't do before.
HTML
<li order="" class="field-dropped text" ng-repeat="field in theForm.fields" ng-switch="theForm.field.type">
<div class="field-actions"><i class="icon-edit"></i> <i class="icon-move"></i> <i class="icon-remove"></i>
</div>
<h4>{{theForm.field.label}}</h4>
<em class="field-desc">{{theForm.field.desc}}</em>
<!-- type: text -->
<input ng-switch-when="text" type="text" placeholder="" disabled class="span6">
<!-- type: para -->
<textarea ng-switch-when="para" type="text" placeholder="" disabled class="span6"></textarea>
<!-- type: drop -->
<select ng-switch-when="drop" placeholder="" disabled class="span6"></select>
<div class="field-options well">
<label>Field Title</label>
<input type="text" placeholder="Field Label" class="span8" ng-model="theForm.field.label">
<label>Field Description</label>
<textarea class="description span8" type="text" placeholder="Field Description" ng-model="theForm.field.desc"></textarea>
<label class="checkbox">
<input type="checkbox" value="" ng-model="theForm.field.req">Required?</label>
<!-- type: drop -->
<label ng-switch-when="drop" class="checkbox">
<input type="checkbox" value="" ng-model="theForm.field.dropOptionsMul">Allow Multiple Choices?</label>
<label ng-switch-when="drop">Options</label>
<em ng-switch-when="drop">Enter a new option on each line.</em>
<textarea ng-switch-when="drop" class="span6" type="text" placeholder="Options" ng-list="
" ng-trim="false" ng-model="theForm.field.dropOptions"></textarea>
</div>
<input class="sortOrder" id="" name="" value="" type="hidden">
</li>
JS
angular.module('formApp', [])
.controller('formController', ['$scope', function($scope) {
$scope.theForm = {
formTitle: '',
formDesc: '',
fields: []
};
$scope.addField = function(ui) {
var type = ui.draggable.attr("id");
console.log(type);
$scope.theForm.fields.push({type: type, label:'Added Form Title', desc:'Added Form Desc', req:false});
console.log("for-break");
};
}])
.directive('drag', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
$( elem ).draggable({
helper: "clone",
activeClass: "ui-state-default",
hoverClass: "ui-state-hover",
drop: function( event, ui ) {
}
});
}
}
})
.directive('drop', function() {
return {
restrict: "A",
link: function(scope, elem, attrs) {
$( elem ).droppable({
hoverClass: "holder-state-highlight",
drop: function(event, ui) {
//handleDropEvent(event, ui);
//sortOrder();
scope.$apply(function(){
angular.element('#theForm').scope().addField(ui);
});
}
});
}
}
});
JSON Output
{
"formTitle": "",
"formDesc": "",
"fields": [],
"field": {
"label": "The actual field title",
"desc": "The actual field description"
}
}
ng-repeat="field in theForm.fields"
field becomes the 'shortcut' for each object in theForm.fields.
So inside ng-repeat you call it just by type.
It's like saying
for (i = 0; i < theForm.fields.length; i++) {
var field = theForm.fields[0];
// from now on you access it by field
field.type = 'My Type';
}

inherit angularjs functions in all child elemts

I've created a directive that show a calender like this :
app.directive('noeDatepicker', ['$parse', 'datetimeService', function ($parse, datetimeService) {
return {
restrict: 'E',
templateUrl: '/app/directives/templates/datepicker.html',
scope: {
model: '=',
withisrequired: '#'
},
require: '^form',
replace: true,
link: function (scope, element, attrs, ctrl) {
scope.buttonId = 'date_icon_' + attrs.id;
scope.inputId = 'date_input_' + attrs.id;
scope.cancelId = 'date_cancel_' + attrs.id;
setTimeout(function () {
Calendar.setup({...});
}
};
}
});
and my template is this :
<div ng-model="model" class="form-inline">
<input id="{{inputId}}" class="form-control" type="text" isrequired="{{withisrequired}}" ng-model="model" placeholder="1111/01/01" />
<img id="{{cancelId}}" src="/Content/noe/assets/image/icon/Cancle.svg" width="22" height="22" />
<img id="{{buttonId}}" src="/Scripts/jalalijscalendar/cal.png" />
</div>
but my problem is that when I wanna add for example ng-readonly to this directive, it just add readonly property to div element and input element is not readonly and it accept input from user (see code bellow) :
<noe:datepicker model="viewModel.date" id="date1" name="date1" ng-readonly="true" />
I want this ng-readonly function also make all child element in div tag readonly and not just add readonly proptety to div element!
How can i Do that ?
Update noeDatepicker with
scope:{
readonly:'=ngReadonly',
...
},
template: <div> <input ng-readonly="readonly"/> </div> ...
basically, you need to add ng-readonly for children elements you want to set.

Categories

Resources