Attribute directive in AngularJS - javascript

I am trying to create a attribute directive that will insert a label before the input field. Judging by the alert statement, the html looks correct. However I am not compiling or doing the angular element correctly. Any help would would be much appreciated.
The fiddle is http://jsfiddle.net/2suL9/
This is the JS code.
var myApp = angular.module('myApp', []);
myApp.directive('makeLabel', function ($compile) {
return {
restrict: 'A',
replace: false,
link: function (scope, inputFld, attrs) {
var ForInput = attrs['name'];
var LabelSize = attrs['labelSize'];
var LabelText = attrs['makeLabel'];
var htmlStart = '<label for="' + ForInput + '" class="label-control ' + LabelSize + '">';
var htmlStar = '';
if (attrs['required'] ) {
htmlStar = '<span style="color:red">*</span>';
}
var htmlEnd = LabelText + ":</label> ";
var htmlTotal = htmlStart + htmlStar + htmlEnd;
alert(htmlTotal);
// Now add it before the input
var newLabel = angular.element(htmlTotal);
inputFld.prepend(($compile(htmlTotal)));
}
};
});
This is the HTML
<!DOCTYPE html>
<html class="no-js" data-ng-app="myApp">
<head>
<title></title>
</head>
<body>
<div class="container">
<div class="row">
<form name="TestLabelForm" class="form-horizontal">
<div class="form-group">
<input type="text" name="Simple" required="" make-label="Test Label" label-size="col-md-7" />
</div>
</form>
</div>
<br />
Should look like
<br />
<div class="row">
<form name="ExampleForm" class="form-horizontal">
<div class="form-group">
<label for="Simple2" class="col-md-7"><span style="color:red">*</span>Test Label:</label>
<input type="text" name="Simple2" required="" />
</div>
</form>
</div>
</div>
<!-- Get Javascript -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js">
</script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.18/angular.min.js"> </script>
<script src="js/TestLabelAttr.js"> </script>
</body>
</html>

Did you see the DOM Exception, which was thrown? It could not find the elements, which you created. You have to use document.createElement() and introduce the newly created element to the scope via $compile(scope)(newElement). Here is a working fiddle of this: http://jsfiddle.net/2suL9/26/ Please note that I didn't implement the if condition of your example, you have to add it!
The javascript part looks like this:
var myApp = angular.module('myApp', []);
myApp.directive('makeLabel', function ($compile) {
return function (scope, inputFld, attrs) {
var el = inputFld[0];
var newEl = document.createElement("label");
newEl.setAttribute("for", attrs['name']);
newEl.setAttribute("class", "label-control");
var subEl = document.createElement("span");
subEl.setAttribute("style", "color:red");
subEl.innerHTML = "*";
var endText = document.createTextNode("Test Label:");
$compile(scope)(newEl);
$compile(scope)(subEl);
$compile(scope)(endText);
newEl.appendChild(subEl);
newEl.appendChild(endText);
inputFld.parent().prepend(newEl);
}
});
Note: Changing the dom elements outside of the directive is not a good practice. Rather use another directive for the label, which should be shown in front of the input. You can centralise the logic in your controller and use broadcast to inform the directives, when they should change.

Related

Put the value of an input into another input form in AngularJS

Having this js fiddle
var app = angular.module('myApp', []);
app.controller('MyController', ['$scope', MyController]);
function MyController($scope) {
$scope.value1 = $scope.value1;
$scope.value2 = "this is it: " + $scope.value1;
}
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js">
</script>
<div ng-controller='MyController'>
<h1>Introduce your value:</h1>
<input type="text" ng-model="value1"></input></br>
<input type="text" ng-model="name" ng-change="value1"></input>
</div>
</html>
I want to introduce a value in the first input and to get it into the next one as "this is it: firstvalue".
You can achieve that easily using ng-change and using ng-model properly
var app = angular.module('myApp', []);
app.controller('MyController', ['$scope', MyController]);
function MyController($scope) {
$scope.value1 = undefined;
$scope.value2 = undefined;
$scope.onValue1Change = function(){
$scope.value2 = "this is it: " + $scope.value1;
};
}
<html ng-app="myApp">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js">
</script>
<div ng-controller='MyController'>
<h1>Introduce your value:</h1>
<input type="text" ng-model="value1" ng-change="onValue1Change()"></input></br>
<input type="text" ng-model="value2"></input>
</div>
</html>

Click to delete dynamically created element in AngularJS

Currently whatever the user enters in the text box and clicks the button, is being displayed inside anchor tags dynamically (all in new lines).
Textbox and the button (HTML file)-
<input type="text" name="inputText"><br>
<tr>
<input type="button" value="ADD" ng-click="$ctrl.addtext()">
</tr>
<div id="outputDiv"></div>
JS function-
ctrl.addtext = function () {
var div = document.getElementById('outputDiv');
div.innerHTML += "<a href='' style='margin-left:10px'>"+newtext+"</a><br>";
}
Is there a way to add a close/remove button (like an X) at end of the dynamically created anchor tags, that On-click remove those particular rows of only?
Edit 3
Using a different component syntax:
function scanExceptionComponentCtrl ($scope, $compile) {
var ctrl = this;
ctrl.addtext = function (e) {
var newtext = document.listForm.inputText.value
var outputDiv = $('#outputDiv');
var newRow = $compile("<a href='' style='margin-left:10px'>"+newtext+" - <span ng-click='$ctrl.removeRow($event)'>X</span></a><br>")($scope);
newRow.appendTo(outputDiv)
};
ctrl.removeRow = function(e) {
e.preventDefault();
e.target.parentNode.remove();
};
};
// angular.module('consoleApp', [])
angular.module('consoleApp',[])
.component('scanException', {
templateUrl: 'templateId',
controller: scanExceptionComponentCtrl
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>
<div ng-app="consoleApp">
<scan-exception></scan-exception>
<script type="text/ng-template" id="templateId">
<form name="listForm">
<table border="0" cellspacing="0">
<tr>
<input type="radio" style="margin-left:10px;" name="checkRadio" value="append" checked><span class="add-file-text" style="font-weight:bold;">Add File to Exception List</span><br>
<input type="text" style="width:250px;height:30px;margin-left:10px;margin-top:10px;" name="inputText"><br>
</tr>
<tr>
<input type="button" style="margin-left:10px;margin-top:10px;" value="ADD" ng-click="$ctrl.addtext($event)">
</tr>
<tr>
<td>
<div id="outputDiv"></div>
</td>
</tr>
</table>
</form>
</script>
</div>
Edit 2 - updates to use jQuery syntax and pass $scope into $compile
add an ng-click and use $compile (make sure to include in controller)
ctrl.addtext = function () {
var outputDiv = $('#outputDiv');
var newRow = $compile("<a href='' style='margin-left:10px'>" + 'newtext ' + " <span ng-click='removeRow($event)'>X</span></a><br>")($scope);
newRow.appendTo(outputDiv)
};
create function
I'm not sure exactly what element you wanted to remove.
ctrl.removeRow = function(e) {
e.preventDefault();
e.target.parentNode.remove();
};
Code Snippet
There may be differences in how you are writing your components/controllers.
angular.module('myApp', [])
.controller('myController', function ($scope, $compile) {
$scope.addText = function () {
var outputDiv = $('#outputDiv');
var newRow = $compile("<a href='' style='margin-left:10px'>" + 'newtext ' + " <span ng-click='removeRow($event)'>X</span></a><br>")($scope);
newRow.appendTo(outputDiv)
};
$scope.removeRow = function(e) {
e.preventDefault();
e.target.parentNode.remove();
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<button ng-click="addText($event)">add text</button>
<div id="outputDiv"></div>
</div>
You can use the $event property in angular or something like a html-5 data attribute to retrieve the info of the clicked element. Roughly your code would look like this:
HTML:
<input type="button" value="ADD" ng-click="$ctrl.addtext($event)">
and JS
ctrl.addtext = function (event) {
var clickedElem = document.getElementById(event.target.id);
// do whatever you want with the element.
var div = document.getElementById('outputDiv');
div.innerHTML += "<a href='' style='margin-left:10px'>"+newtext+"</a><br>";
}

How to add input forms dynamically in Angular JS

I want to change the form inputs dynamically , and i have tried doing it using ng-bind-html , but only label is getting displayed , text box doesn't appears on the DOM. Here what has to be written inside ctrl.content depends upon the values from the server.
Note
type value will be coming from server , and it can be dynamic
HTML
<div ng-bind-html="ctrl.content">
Controller
function myCtrl(type) {
var ctrl = this;
switch (type) {
case 1:
ctrl.content = " <div> Input : <input type=\"text\" > </div> ";
break;
case 2:
ctrl.content = " <div> Input : <input type=\"textarea\" > </div> ";
break;
default:
}
Dom Element :
<div class="padding ng-binding ng-scope" ng-bind-html="addMeassurments.content"> <div> Input : </div> </div>
First, your assignment is all wrong
ctrl.content = " <div> Input : <input type=\"text\" > </div> ";
You should be assigning the markup to a $scope property. e.g.
$scope.content = " <div> Input : <input type=\"text\" > </div> ";
Secondly you should use the $sce service to sanitize the html. Here's a plnkr where this code demonstrates the intended behavior
var app = angular.module('plunker', []);
app.controller('Ctrl', function($scope, $sce) {
$scope.name = 'World';
var ctrl = this;
$scope.click = function myCtrl(type) {
switch (type) {
case 1:
$scope.content = $sce.trustAsHtml("<div> Input : <input type=\"text\" > </div> ");
break;
case 2:
$scope.content = $sce.trustAsHtml(" <div> Input : <textarea></textarea> </div> ");
break;
default:
}
}
});
Note also that I changed your markup from input type="textarea" to a textarea element.
You should use $sce service with ngSanitize module:
angular.module('app', ['ngSanitize'])
.controller('MyController', ['$scope', '$sce', function($scope, $sce) {
$scope.html = function(){
return $sce.trustAsHtml(`<div> Input : <input type=\"${$scope.type == 0 ? 'text' : 'textarea'}\" > </div>`);
}
}]);
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="//code.angularjs.org/snapshot/angular-sanitize.js"></script>
<body ng-app="app">
<div ng-controller="MyController" ng-init='type="0"'>
text: <input type="radio" ng-model="type" value="0">
textarea: <input type="radio" ng-model="type" value="1">
<div ng-bind-html="html()"></div>
</div>
</body>
A textarea can not render HTML input type like <input type=\"textarea\" >..
and try with $sce.
var app = angular.module('exApp',[]);
app.controller('ctrl', function($scope,$sce){
$scope.text = $sce.trustAsHtml("<div> Input : <input type=\"text\" > </div> ");
$scope.textArea = $sce.trustAsHtml(" <div> Input : <textarea></textarea> </div> ");
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="exApp" ng-controller="ctrl">
<div ng-bind-html="text"></div><br>
<div ng-bind-html="textArea"></div><br>
</body>
Use ng-if instead of ng-bind-html.
Something like this:
<div>
<div ng-if="type===1">Input : <input type="text"></div>
<div ng-if="type===2">Input : <input type="textarea"></div>
</div>
And in your controller, you will only need to dynamically assign type either 1 or 2 as value.

How to Change each Appended text Angularjs

I'm not getting result properly using append event instead of using ng-repeat in adding each name. Can you please help me how can I change added each name from a single input field. Tell me without using ng-repeat in this because ng-repeat functionality is not working to me for my further running functionalities, you can solve this using jquery or javascript if it's possible without using ng-repeat. Thanks in advance..
Here is JSBin
var app = angular.module('myapp', ['ngSanitize']);
app.controller('AddCtrl', function ($scope, $compile) {
$scope.my = {name: 'untitled'};
$scope.add_Name = function (index) {
var namehtml = '<label ng-click="selectName($index)">{{my.name}} //click<br/></label>';
var name = $compile(namehtml)($scope);
angular.element(document.getElementById('add')).append(name);
};
$scope.selectName = function (index) {
$scope.showName = true;
};
});
<!DOCTYPE html>
<html ng-app="myapp">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.2/angular.min.js"></script>
<script src="https://code.angularjs.org/1.5.0-rc.0/angular-sanitize.min.js"></script>
</head>
<body ng-controller="AddCtrl">
<button ng-click="add_Name($index)">Add Names</button>
<div id="add"></div><br/>
<form ng-show="showName">
<label>Name Change(?)</label><br/>
<input ng-model="my.name">
</form>
</body>
</html>
If I understand what you're looking for correctly this should work.
HTML:
<body ng-controller="AddCtrl">
<button ng-click="add_Name()">Add Names</button>
<div ng-repeat="item in names">
<label ng-click="selectName($index)">{{$index}}- {{item}} //click to change<br/></label>
</div>
<form ng-show="showName">
<label>Name Change at index {{nameIndex}}</label><br/>
<input ng-model="names[nameIndex]">
</form>
</body>
JS:
$scope.names = [];
$scope.add_Name = function(index){
$scope.names.push('untitled')
}
$scope.selectName = function (index) {
$scope.nameIndex = index;
$scope.showName = true;
};

apply ng-show and ng-hide on condition based for dynimcally created elements angular js ng-repeat

apply required filed for some filed in my form but my form is created using the custom directive, So Html is created Dynamically. I am using ng-repeat, i need to show some fields are required when user enter the submit button, but it is showing all fields is required.
<div ng-repeat="item in items">
<input type=[item.name]>
</div>
<p ng-show="ErrorMsg">Error Message </p>
when i am checking the controller logic
Controller.js
$scope.ErrorMsg = false;
if(item.value == null){
$scope.ErrorMsg = true;
}
But it is showing all fields for error msg. Please suggest me how to approach
Thanks in Advance!
I create a simple plunkr about angularjs dynamic form validation, please refer here:http://plnkr.co/edit/7OJHKsJPoHNqeeStBtnh.
// Code goes here
var myApp = angular.module('myApp',[]);
myApp.controller('DemoController', ['$scope', function($scope) {
function setTouched(form) {
angular.forEach(form, function (value, key) {
if (!/^\$/.test(key)) {
form[key].$setTouched();
}
});
}
var config = [];
for (var i = 0; i < 10; i++) {
var item = {};
item.name = 'input' + i;
item.required = (i%2 === 0) ? true : false;
config[i] = item;
}
$scope.config = config;
$scope.save = function() {
if ($scope.testForm.$invalid) {
setTouched($scope.testForm);
}
}
}]);
<!DOCTYPE html>
<html ng-app="myApp">
<head>
<script data-require="angularjs#1.3.6" data-semver="1.3.6" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.6/angular.min.js"></script>
<script data-require="ng-messages#*" data-semver="1.3.16" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.16/angular-messages.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="DemoController">
<form name="testForm" ng-submit="save()" novalidate>
<div ng-repeat="item in config">
<input type="text" name="{{item.name}}" ng-model="item.value"
ng-required="item.required" />
<div ng-messages="testForm[item.name].$error"
ng-if="testForm[item.name].$invalid && testForm[item.name].$touched">
<div ng-message="required">this is required</div>
</div>
</div>
<button type="submit">save</button>
</form>
</body>
</html>
Hope this can help :)

Categories