How to change template URL at runtime in AngularJS? - angularjs

I have in app.js
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope) {
// Fetch the data from the API calls
var empDept = GetEmployeeData();
var marFin = GetFinanceData();
var x = 1;
$scope.list = {};
switch(x)
{
case 1: $scope.list = {
EmployeeDepartment: empDept
}; break;
case 2:
$scope.list = {
MarketingFinance: marFin
};break;
}
});
app.directive('myCustomer', function() {
return {
restrict: 'AE',
scope: {
customer: '=myCustomer'
},
replace: true,
templateUrl: 'EmpDept.html'
}
};
});
And my index.html is as under
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<script data-semver="1.3.15" src="https://code.angularjs.org/1.3.15/angular.js" data-require="angular.js#1.3.x"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<label ng-repeat="(key,val) in list">
<div ng-if="key === 'EmployeeDepartment'">
<table border="1">
<tr>
<td><b>EmployeeNames</b></td>
</tr>
<tbody>
<tr ng-repeat="customer in val" my-customer="customer"></tr>
</tbody>
</table>
<script type="text/ng-template" id="EmpDept.html">
<tr>
<td>{{customer.EmpName}}</td>
</tr>
</script>
</div>
<div ng-if="key === 'MarketingFinance'">
<table border="1">
<tr>
<td><b>Product Name</b></td>
<td><b>Price</b></td>
</tr>
<tbody>
<tr ng-repeat="customer in val" my-customer="customer"></tr>
</tbody>
</table>
<script type="text/ng-template" id="MarkFin.html">
<tr>
<td>{{customer.ProductName}}</td>
<td>{{customer.Price}}</td>
</tr>
</script>
</div>
</label>
</html>
Now the problem is that
Depending on the value of the switch case, the templateURL has to be changed.
e.g
if x=1, templateURL = EmpDept.html
if x=2, templateURL = MarkFin.html
Can you please tell how to do it?
N.B.~ I have seen this but could not plug into the application. Any other easy way?

I have added a plunker that allows you to dynamically change the template URL
http://plnkr.co/edit/yG5qEbFORyyNnCdVDOOY?p=preview
You must add the variable that stores the html link to the directive scope as you can see below:
app.directive('myCustomer', function() {
return {
restrict: 'AE',
scope: {
customer: '=myCustomer',
templateHtml: "="
},
replace: true,
template: '<div ng-include="templateHtml"></div>',
link: function(scope, element, attrs) {
}
};
});

Related

Post data of form created by ng-repeat

I have one input field =, one checkbox and one file upload option per row of table and the rows are created by ng-repeat .
<tr data-ng-repeat="choice in choices track by $index">
<td><input type="textbox" size="50" class="des-textinput" required></td>
<td><input type="checkbox" required></td>
<td><input type="file" class="photo-upload" ></td>
</tr>
My question is how to post the datas to backend via one submit button as it is created by ng-repeat and it will be multiple.
For starters bind your inputs to the model using ng-model. Then create a directive that will bind the file input to the model. Lastly, call a function from your submit button that will iterate through the model and call an upload service for each file.
var app = angular.module('uploadApp', []);
app.controller('MainCtrl', function($scope) {
$scope.choices = [{
desc: 'file 1',
include: false,
file: null
}, {
desc: 'file 2',
include: false,
file: null
}, {
desc: 'file 3',
include: false,
file: null
}];
$scope.uploadFiles = function() {
$scope.choices.forEach(f => {
const file = f.file;
if (file) {
// call upload function from here
console.log('Upload: ', file);
}
});
};
});
app.directive("fileInput", function() {
return {
require: "ngModel",
restrict: 'A',
link: function postLink(scope, element, attrs, ngModel) {
element.on("change", function(e) {
var file = element[0].files[0];
ngModel.$setViewValue(file);
});
}
};
});
<!DOCTYPE html>
<html ng-app="uploadApp">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js#1.5.x" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.11/angular.min.js" data-semver="1.5.11"></script>
</head>
<body ng-controller="MainCtrl">
<table>
<tr data-ng-repeat="choice in choices track by $index">
<td>
<input type="textbox" size="50" class="des-textinput" ng-model="choice.desc" required />
</td>
<td>
<input type="checkbox" required ng-model="choice.include" />
</td>
<td>
<input type="file" class="photo-upload" ng-model="choice.file" file-input/>
</td>
</tr>
</table>
<button ng-click="uploadFiles()">Submit</button>
</body>
</html>

How to get contentEditable element's updated value in angular js?

var myApp = angular.module("problemApp", []);
myApp.controller("RESTCall", function ($scope, $compile, $element, $timeout) {
$scope.username = 'Adan';
console.log($scope.username)
$scope.printValue = function(data) {
$timeout(function () {
$scope.$apply(function(){
console.log(data);
});
});
}
});
table td, th{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<div ng-app="problemApp">
<div ng-controller="RESTCall">
<form name="covertToProForm" id=
"table-print">
<table id="confirm">
<tr>
<th>Firstname</th>
<td contentEditable ng-keyup="printValue(username)" ng-model="username">{{username}}</td>
</tr>
<tr>
<th>Lastname</th>
<td>Smith</td>
</tr>
</table>
</form>
</div>
</div>
I have the above table which has a td, that has contentEditable attribute. On editing td's value, I want to print its value in console. Any help would be appreciated!
Edited snippet with the given answer. It's not working.
Please disregard my previous answer. The whole thing is we need to wrap contenteditable in a custom directive because contenteditable directive does not not work directly with angular's ng-model just because it re-render the dom element on every change, resulting in loosing the recent ng-model change.
here's a new wrapper around contenteditable
var app = angular.module('app', []);
app.directive('contenteditable', function() {
return {
restrict: "A",
require: 'ngModel',
controller: function($scope) {
$scope.username = 'Adan';
$scope.printValue = function() {
console.log($scope.username);
}
},
link: function(scope, element, attrs, myController) {
element.on('keyup', function() {
scope.$apply(updateViewModel);
});
function updateViewModel() {
var htmlValue = element.text()
myController.$setViewValue(htmlValue);
scope.printValue();
}
myController.$render = updateHtml
function updateHtml() {
var viewModelValue = myController.$viewValue
element.text(viewModelValue);
}
}
};
});
<!DOCTYPE html>
<html ng-app="app">
<head>
<script data-require="angular.js#1.2.7" data-semver="1.2.7" src="https://code.angularjs.org/1.2.7/angular.js"></script>
<link href="style.css" rel="stylesheet" />
<script src="script.js"></script>
</head>
<body>
<div>
<h2>{{username}}</h2>
<form>
<table>
<tr>
<th>Firstname</th>
<td contenteditable ng-model="username">{{username}}</td>
</tr>
<tr>
<th>Lastname</th>
<td>Smith</td>
</tr>
</table>
</form>
</div>
</body>
</html>

Directive not rendering inside ng-repeat

The directive test-dir fails to render
<ul>
<li ng-repeat="person in data">
<table>
<thead>{{person.name}}</thead>
<tbody>
<tr ng-repeat="row in person.entries">
<test-dir data="row"></test-dir>
</tr>
</tbody>
</table>
</li>
</ul>
app.directive("testDir", function(){
return {
restrict: 'EA',
scope: {
data: '='
},
template: "<td>{{data}}</td>"
};
});
It does render when used as an attribute. Not sure why it wouldn't work as an element.
PLNKR: http://plnkr.co/edit/fraBDzt9kjZlUIuV1fDf?p=preview
First, you need to add replace: true to testDir directive.
Otherwise you'll have a <div> inside a <tr> which is why the directive is not rendered when used as element.
However, even with replace: true you will encounter a known bug:
Error: Template must have exactly one root element. was: <td>{{data}}</td>
Better use the directive as attribute.
Just use ng-repeat with directive like <test-dir ng-repeat="row in person.entries" data="row"></test-dir>
So your code will be
<!doctype html>
<html ng-app="plunker" >
<head>
<meta charset="utf-8">
<title>AngularJS Plunker</title>
<script>document.write("<base href=\"" + document.location + "\" />");</script>
<link rel="stylesheet" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.js"></script>
<script>
var app = angular.module('plunker', []);
app.directive("testDir", function(){
return {
restrict: 'EA',
scope: {
data: '='
},
template: "<td>{{data}}</td>"
};
});
app.controller('MainCtrl', function($scope) {
$scope.name = 'World';
$scope.data = [
{
name: 'cars',
entries: [
{model: 'fiat', speed: 100 },
{model: 'tesla', speed: 200 },
]
},
{
name: 'trucks',
entries: [
{model: 'volvo', speed: 50 },
{model: 'merc', speed: 75 },
]
}
];
});
</script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<ul>
<li ng-repeat="person in data">
<table>
<thead>{{person.name}}</thead>
<tbody>
<tr >
<test-dir ng-repeat="row in person.entries" data="row"></test-dir>
</tr>
</tbody>
</table>
</li>
</ul>
</body>
</html>

nvD3 bullet chart is not showing up

i am using angualr nvD3 directory for bullet chart. i want to dispaly the data in the form of bullet chart in a table.
var app = angular.module('plunker', ['nvd3']);
app.controller('MainCtrl', ['$scope','$http', function ($scope, $http ) {
$scope.LoadInit = function () {
//alert('1');
$scope.jsondata = [{'transactionName': '1',
'actualVolume':'150',
'expectedVolume':'300'
},
{
'transactionName': '2',
'actualVolume':'250',
'expectedVolume':'300'
}
]
$scope.transactionData= $scope.jsondata;
.finally(function(){
$scope.data1 = {
//"title": "Revenue",
//"subtitle": "US$, in thousands",
"ranges": [0,100,1300],
"measures": [record.actualVolume],
"markers": [record.expectedVolume]
};
});
$scope.options1 = {
chart: {
type: 'bulletChart',
transitionDuration: 1
}
};
};
$scope.LoadInit();
}]);
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>Angular-nvD3 Bullet Chart</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.css"/>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/nvd3/1.8.1/nv.d3.min.js"></script>
<script src="https://rawgit.com/krispo/angular-nvd3/v1.0.4/dist/angular-nvd3.js"></script>
<script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
<div class="panel-body" style="margin-top: 10px">
<table class="table text-center">
<thead>
<tr>
<th> tname</th>
<th> volume</th>
<th>graph</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="record in transactionData">
<td>{{record.transactionName}}</td>
<td>{{record.actualVolume}}</td>
<td><nvd3 options="options1" data="data1"></nvd3></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
but i am not getting the data when i tried to use bullet chart, other wise i am getting data. when i am using http call for data rather than json object, following error is coming.click here for error page
Here is a simplified version of what I think you were trying to achieve. I don't quite get the .finally() function in your code, so what I do instead is map $scope.jsondata to $scope.transactionData, creating a chartData property within each item, so that when you ng-repeat over them, you can feed each of the nvd3 bullet charts its own data object.
I believe the errors you were getting were caused by the fact that you were trying to feed string values of actualVolume and expectedVolume to nvd3, so I fixed that by converting them to Number values instead:
chartData: {
ranges: [100, 150, Number(record.expectedVolume)*1.5],
measures: [Number(record.actualVolume)],
markers: [Number(record.expectedVolume)]
}
See the rest below... Hope this helps you.
var app = angular.module('plunker', ['nvd3']);
app.controller('MainCtrl', ['$scope', function ($scope) {
$scope.jsondata = [
{
'transactionName': '1',
'actualVolume':'150',
'expectedVolume':'300'
},
{
'transactionName': '2',
'actualVolume':'250',
'expectedVolume':'300'
}
];
$scope.transactionData = $scope.jsondata.map(function(record) {
return {
transactionName: record.transactionName,
actualVolume: record.actualVolume,
expectedVolume : record.expectedVolume,
chartData: {
ranges: [100, 150, Number(record.expectedVolume)*1.5],
measures: [Number(record.actualVolume)],
markers: [Number(record.expectedVolume)]
}
};
});
$scope.options1 = {
chart: {
type: 'bulletChart',
transitionDuration: 500
}
};
}]);
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>Angular-nvD3 Bullet Chart</title>
<link data-require="nvd3#1.8.1" data-semver="1.8.1" rel="stylesheet" href="https://cdn.rawgit.com/novus/nvd3/v1.8.1/build/nv.d3.css" />
<script data-require="angular.js#1.3.9" data-semver="1.3.9" src="https://code.angularjs.org/1.3.9/angular.js"></script>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<script data-require="nvd3#1.8.1" data-semver="1.8.1" src="https://cdn.rawgit.com/novus/nvd3/v1.8.1/build/nv.d3.js"></script>
<script src="https://rawgit.com/krispo/angular-nvd3/v1.0.4/dist/angular-nvd3.js"></script>
</head>
<body ng-controller="MainCtrl">
<div class="panel-body" style="margin-top: 10px">
<table class="table text-center">
<thead>
<tr>
<th> tname</th>
<th> volume</th>
<th>graph</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="record in transactionData">
<td>{{record.transactionName}}</td>
<td>{{record.actualVolume}}</td>
<td class="table-cell-chart">
<nvd3 options="options1" data="record.chartData"></nvd3>
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

AngularJs while replacing the table row - changing html from compile function but scope is not getting linked

Here, I am trying to replace the table row through directive and compile function. Somehow, the scope is not linking to newly added template.
Here is the really simple code.
Created a plnkr here: http://plnkr.co/edit/toAxkoLkWSIxYJU06iuW?p=preview
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
<!-- <script src="app.js"></script>-->
</head>
<body>
<h1> stand alone </h1>
<!-- <row></row>
-->
<h1>in table</h1>
<table>
<tr><td> Row 1</td></tr>
<tr sda-data-embed='true' row><td>my row goes here</td></tr>
<tr><td> Row 4</td></tr>
</table>
<script>
var app = angular.module('plunker', []);
app.directive('row', function($compile) {
var template = '<tr><td>Row 2: This is good</td></tr><tr><td>Row 3: {{name.firstName}}</td></tr>';
return {
restrict: 'EA',
replace: true,
scope:{},
/*template: function(element, attrs) {
var templ = template;
if (!attrs.sdaDataEmbed) {
templ = '<table>' + template + '</table>';
}
return templ;
},*/
compile: function(element, attrs) {
//$scope.firstName = 'Y';
var templ = template;
if (!attrs.sdaDataEmbed) {
templ = '<table>' + template + '</table>';
}
element[0].outerHTML = templ;
},
controller: ['$scope', DataController]
}
function DataController($scope) {
$scope.name = {};
$scope.name.firstName = 'Gosh';
}
});
</script>
</body>
</html>
UPDATE : Later I found how to replace the table row, not sure if it is recommended but it works!
I replaced, compiled the html element from link function.
here is the code.
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<script>
document.write('<base href="' + document.location + '" />');
</script>
<link rel="stylesheet" href="style.css" />
<script data-require="angular.js#1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>
<!-- <script src="app.js"></script>-->
</head>
<body>
<h1> stand alone </h1>
<div>
<my-row></my-row>
</div>
<h1>in table</h1>
<table>
<tr>
<td>Row 1</td>
</tr>
<tr sda-data-embed='true' my-row>
<td>my row goes here</td>
</tr>
<tr>
<td>Row 4</td>
</tr>
</table>
<script>
var app = angular.module('plunker', []);
app.directive('myRow', function($compile) {
var template = '<tr><td>Row 2: This is good</td></tr><tr><td>Row 3: {{name.firstName}}</td></tr>';
return {
restrict: 'EA',
replace: true,
scope: {},
link: function(scope, element, attrs) {
var templ = template;
if (!attrs.sdaDataEmbed) {
templ = '<table>' + template + '</table>';
}
var e = $compile(templ)(scope);
element.replaceWith(e);
},
controller: ['$scope', DataController]
}
function DataController($scope) {
$scope.name = {};
$scope.name.firstName = 'Gosh';
}
});
</script>
</body>
</html>
in your compile function instead of doing the HTML manipulation return an object with the pre and post properties
compile: function compile(tElement, tAttrs, transclude) {
return {
pre: function preLink(scope, iElement, iAttrs, controller) { ... },
post: function postLink(scope, iElement, iAttrs, controller) { ... }
}
// or
// return function postLink( ... ) { ... }
}
then perform the html manipulation on the pre: function this will allow you to manipulate the dom pre-link
https://docs.angularjs.org/api/ng/service/$compile

Resources