adding element to parent from directive - html

In order to disable the auto complete of chrome in forms, i want to create angular directive which add dummy input element
my code is
`angular.module("noc.components").directive('customInput', function ($compile) {
"use strict";
return {
restrict:'E',
template:'<input>',
replace:true,
link: function(scope, elem) {
//scope.type = attrs.type || 'email';
var el = angular.element('<input name={{type}} style="display: none">');
//var type = elem[0].name;
$compile(el)(scope);
elem.parent().append(el);
}
};
});`
and the html is
<div class="form-group">
<label for="setupWizardUserStepEmail">Email Address</label>
<custom-input class="form-control"
id="setupWizardUserStepEmail"
ng-model="setupRequest.userRequest.email"
name="email"
ng-required="true"
noc-validation="email"
autocomplete="off"
autofocus="true">
</div>
however the injected html isnt in the parent - i want it to be above the directive
how can i do it?

I was able to solve my own problem in the end:
I changed it to elem.parent().prepend(el);

Related

Binding on change event to dynamically created divs

I'm trying to generate divs dynamically (by input) inside another div created dynamically by the user. The problem is that I'm able to generate both divs dynamically, buy the child divs are not going to create any divs by input.
The second one id="usersvmaddnewdivsN" is not going to generate any divs. Can you help me please? Thank you.
(check jsfiddle to understand better)
https://jsfiddle.net/rqebwm59/3/
$(function() {
$(".instancesN").change(function() {
var value = $(this).val();
$(".instancesNContainer").empty();
for (var i = 1; i < value; i++) {
var block = $("<div>", {
class: "block"
});
$(block).append($("div.instancesNSpecifics").html());
$(".instancesNContainer").prepend(block);
}
});
});
$(function() {
$("#usersvmaddnewdivsN").change(function() {
var value = $(this).val();
$(".usersvmaddnewdivsNContainer").empty();
for (var i = 1; i < value; i++) {
var block = $("<div>", {
class: "block"
});
$(block).append($("div.usersvmaddnewdivsNSpecifics").html());
$(".usersvmaddnewdivsNContainer").append(block);
}
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type='number' min="1" oninput="validity.valid||(value='1');" value="1" name='instancesN[]' placeholder="Instances #" class='instancesN' class="form-control" />
<div class="instancesNContainer"></div>
<div class='instancesNSpecifics'>
<input type='number' min="1" oninput="validity.valid||(value='');" name='usersvmaddnewdivsN[]' id='usersvmaddnewdivsN' placeholder="Add new Users" class="form-control" />
</div>
<div class="usersvmaddnewdivsNContainer"></div>
<div class='usersvmaddnewdivsNSpecifics'>
<div class="form-row">
<div class="col">
<input type="text" class="form-control" name='usernamevmN[]' id="usernamevmN" placeholder="VM-Username" />
</div>
I think jQuery events delegation is what you are looking for. You may want to modify second 'change' binding to something like:
$(".instancesNContainer").on('change', '.usersvmaddnewdivsN', function() { //etc.
So every dynamically created .usersvmaddnewdivsN inside its static parent .instancesNContainer will get change event automatically bound.

Call function when control is shown

I have input control:
<input id="someID" class="form-control" type="text" name="SomeData"
data-ng-model="vm.SomeData">
and I need to initialize value vm.SomeData when user will scroll down to this control. I am new in angular, so not sure is there some event like 'ControlDisplayed'?
//html
<input id="someID" when-scrolled="vm" class="form-control" type="text" name="SomeData" data-ng-model="vm.SomeData">
//try this directive
app.directive("whenScrolled", function(){
return {
restrict: 'A',
link: function(scope, elem, attrs){
// we get a list of elements of size 1 and need the first element
raw = elem[0];
// we load more elements when scrolled past a limit
elem.bind("scroll", function(){
if(raw.scrollTop+raw.offsetHeight+5 >= raw.scrollHeight){
scope.vm.name = 'Nainish Modi';
// we can give any function which loads more elements into the list
scope.$apply(attrs.whenScrolled);
}
});
}
}
});

Angularjs : Data binding with HTML generated from a variable

I already apologize for asking, just beginning with angularjs (and client-side dev) and I am trying to do something pretty simple which does not work.
I have some HTML that I want to generate from a variable. This html contains a ng-model directive that I want to bind with some data. Basically if I put directly the html inside the html file, data binding works fine:
HTML
<form role="form" ng-submit="search()" ng-controller="AppController">
<div class="form-group">
<label for="search__origin">Departure</label>
<input type="text" class="form-control" id="search__origin" ng-model="routes[0].origin" /> {{routes[0].origin}}
</div>
</form>
Anjularjs
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.routes = {}
var route_format = {
origin: 'SG',
departure_date: new Date(),
return_date: new Date()
};
$scope.routes['0'] = route
})
Fiddle here
But if I put my HTML (containing a "ng-model" directive) into a $scope variable, then use "ng-bind-html" directive to generate the html directly into the html template, then data binding does not work:
HTML
<form role="form" ng-submit="search()" ng-controller="AppController">
<div class="form-group">
<label for="search__origin">Departure</label>
<div ng-bind-html=myhtml class="form-group"></div>
{{routes[0].origin}}
</div>
</form>
angularjs
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope,$sce) {
$scope.routes = {}
var route_format = {
origin: 'SG',
departure_date: new Date(),
return_date: new Date()
};
$scope.routes['0'] = route_format;
var html = '<input type="text" class="form-control" id="search__origin" ng-model="routes[0].origin"/>'
var getTrustedHtml = function(unsafe_html) {
var x = $sce.trustAsHtml(unsafe_html);
return x;
}
$scope.myhtml = getTrustedHtml(html);
})
Fiddle here
I am wondering here why it does not work, is it because I process in the wrong order and that when the html is generated on the page, the relation with the $scope variable cannot be done?
I would appreciate some help here :), thanks in advance!
Al
ng-bind-html will not compile directives for you.
you need either use $compile service and compile this fragment yourself that is ugly
or
restructure the code not to have directives inside ng-bind
Thanks STEVER for giving me the hint, appreciated!
I have solved my issue using the directive 'ng-include' and creating a html template. It also allows me to iterate ('ng-repeat') over this html template with dynamic 'ng-model's as below:
HTML
<form role="form" ng-submit="search()" ng-controller="AppController">
<div class="form-group">
<div ng-repeat="i in range(route_nb) track by $index">
<div ng-include="'test.html'"></div>
</div>
</div>
{{routes[0].origin}}
{{routes[1].origin}}
</form>
<script type="text/ng-template" id="test.html">
<div class="form-group">
<label for="search__origin">Departure</label>
<input type="text" class="form-control" id="search__origin" ng-model="routes[$index].origin" />
</div>
</script>
jsangular
var app = angular.module('my-app', [], function() {})
app.controller('AppController', function($scope) {
$scope.routes = {};
$scope.route_nb = 2;
$scope.routes['0'] = {
origin: 'SG',
departure_date: new Date(),
return_date: new Date()
};
$scope.routes['1'] = {
origin: 'LON',
departure_date: new Date(),
return_date: new Date()
};
$scope.range = function(n) {
return new Array(n);
};
})
Fiddle
However I am wondering whether it is really efficient in term of performances...

How to convert text to uppercase while typing in input field using angular js

I know that is posible with jquery but I dont know how to do that with angular js, please any sugestion?
function mayuscula(campo){
$(campo).keyup(function() {
$(this).val($(this).val().toUpperCase());
});
}
You can also create a directive for this!
Check the code:
directive('uppercase', function() {
return {
restrict: "A"
require: "?ngModel",
link: function(scope, element, attrs, ngModel) {
//This part of the code manipulates the model
ngModel.$parsers.push(function(input) {
return input ? input.toUpperCase() : "";
});
//This part of the code manipulates the viewvalue of the element
element.css("text-transform","uppercase");
}
};
})
For its usage, here's an example:
<input type="text" ng-model="myModel" uppercase />
You could do it in HTML template or via JS using the angular uppercase filter.
<div>
<label>Input 1</label>
<input type="text" ng-model="first">{{ first | uppercase }}
</div>
If you need to change the value in-place, use toUpperCase when ever value is changed.
<div>
<label>Input 1</label>
<input type="text" ng-model="first" ng-change="text = text.toUpperCase()">
</div>
Above in preferred approaches. Here's yet another way to achieve same result using $watch but this is not recommended. See comments section.
<div>
<label>Input 2</label>
<input type="text" ng-model="second">
</div>
var unwatch = $scope.$watch('second', function(val) {
$scope.second = $filter('uppercase')(val);
}, true);
$scope.$on('$destroy', unwatch);
Related Plunker here http://plnkr.co/edit/susiRn

Edit In Place Content Editing

When using ng-repeat what is the best way to be able to edit content?
In my ideal situation the added birthday would be a hyperlink, when this is tapped it will show an edit form - just the same as the current add form with an update button.
Live Preview (Plunker)
HTML:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="utf-8">
<title>Custom Plunker</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script src="app.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.2.0/css/bootstrap-combined.min.css"
rel="stylesheet">
</head>
<body ng-app="birthdayToDo" ng-controller="main">
<div id="wrap">
<!-- Begin page content -->
<div class="container">
<div class="page-header">
<h1>Birthday Reminders</h1>
</div>
<ul ng-repeat="bday in bdays">
<li>{{bday.name}} | {{bday.date}}</li>
</ul>
<form ng-show="visible" ng-submit="newBirthday()">
<label>Name:</label>
<input type="text" ng-model="bdayname" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bdaydate" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
</form>
</div>
<div id="push"></div>
</div>
<div id="footer">
<div class="container">
<a class="btn" ng-click="visible = true"><i class="icon-plus"></i>Add</a>
</div>
</div>
</body>
App.js:
var app = angular.module('birthdayToDo', []);
app.controller('main', function($scope){
// Start as not visible but when button is tapped it will show as true
$scope.visible = false;
// Create the array to hold the list of Birthdays
$scope.bdays = [];
// Create the function to push the data into the "bdays" array
$scope.newBirthday = function(){
$scope.bdays.push({name:$scope.bdayname, date:$scope.bdaydate});
$scope.bdayname = '';
$scope.bdaydate = '';
};
});
You should put the form inside each node and use ng-show and ng-hide to enable and disable editing, respectively. Something like this:
<li>
<span ng-hide="editing" ng-click="editing = true">{{bday.name}} | {{bday.date}}</span>
<form ng-show="editing" ng-submit="editing = false">
<label>Name:</label>
<input type="text" ng-model="bday.name" placeholder="Name" ng-required/>
<label>Date:</label>
<input type="date" ng-model="bday.date" placeholder="Date" ng-required/>
<br/>
<button class="btn" type="submit">Save</button>
</form>
</li>
The key points here are:
I've changed controls ng-model to the local scope
Added ng-show to form so we can show it while editing
Added a span with a ng-hide to hide the content while editing
Added a ng-click, that could be in any other element, that toggles editing to true
Changed ng-submit to toggle editing to false
Here is your updated Plunker.
I was looking for a inline editing solution and I found a plunker that seemed promising, but it didn't work for me out of the box. After some tinkering with the code I got it working. Kudos to the person who made the initial effort to code this piece.
The example is available here http://plnkr.co/edit/EsW7mV?p=preview
Here goes the code:
app.controller('MainCtrl', function($scope) {
$scope.updateTodo = function(indx) {
console.log(indx);
};
$scope.cancelEdit = function(value) {
console.log('Canceled editing', value);
};
$scope.todos = [
{id:123, title: 'Lord of the things'},
{id:321, title: 'Hoovering heights'},
{id:231, title: 'Watership brown'}
];
});
// On esc event
app.directive('onEsc', function() {
return function(scope, elm, attr) {
elm.bind('keydown', function(e) {
if (e.keyCode === 27) {
scope.$apply(attr.onEsc);
}
});
};
});
// On enter event
app.directive('onEnter', function() {
return function(scope, elm, attr) {
elm.bind('keypress', function(e) {
if (e.keyCode === 13) {
scope.$apply(attr.onEnter);
}
});
};
});
// Inline edit directive
app.directive('inlineEdit', function($timeout) {
return {
scope: {
model: '=inlineEdit',
handleSave: '&onSave',
handleCancel: '&onCancel'
},
link: function(scope, elm, attr) {
var previousValue;
scope.edit = function() {
scope.editMode = true;
previousValue = scope.model;
$timeout(function() {
elm.find('input')[0].focus();
}, 0, false);
};
scope.save = function() {
scope.editMode = false;
scope.handleSave({value: scope.model});
};
scope.cancel = function() {
scope.editMode = false;
scope.model = previousValue;
scope.handleCancel({value: scope.model});
};
},
templateUrl: 'inline-edit.html'
};
});
Directive template:
<div>
<input type="text" on-enter="save()" on-esc="cancel()" ng-model="model" ng-show="editMode">
<button ng-click="cancel()" ng-show="editMode">cancel</button>
<button ng-click="save()" ng-show="editMode">save</button>
<span ng-mouseenter="showEdit = true" ng-mouseleave="showEdit = false">
<span ng-hide="editMode" ng-click="edit()">{{model}}</span>
<a ng-show="showEdit" ng-click="edit()">edit</a>
</span>
</div>
To use it just add water:
<div ng-repeat="todo in todos"
inline-edit="todo.title"
on-save="updateTodo($index)"
on-cancel="cancelEdit(todo.title)"></div>
UPDATE:
Another option is to use the readymade Xeditable for AngularJS:
http://vitalets.github.io/angular-xeditable/
I've modified your plunker to get it working via angular-xeditable:
http://plnkr.co/edit/xUDrOS?p=preview
It is common solution for inline editing - you creale hyperlinks with editable-text directive
that toggles into <input type="text"> tag:
<a href="#" editable-text="bday.name" ng-click="myform.$show()" e-placeholder="Name">
{{bday.name || 'empty'}}
</a>
For date I used editable-date directive that toggles into html5 <input type="date">.
Since this is a common piece of functionality it's a good idea to write a directive for this. In fact, someone already did that and open sourced it. I used editablespan library in one of my projects and it worked perfectly, highly recommended.