Plunker
There are a lot of files, so perhaps you Angular aficionados will understand my explanation, or be able to follow the plunker I've provided above.
I'm creating a demo to modularize a webpage. Even the main content of the page will be in another template file. In the main content view, there's a table of links, the link opens an angular-bootstrap modal (another template/controller), which displays additional information for the object clicked.
I'm finding that every time a link is clicked, the factory is retrieving the source data. For something small, it's unnoticeable, but if you're performing an AJAX request to a large dataset, or transforming an XML to JSON, this could take a while. I am uncertain if this is a result of routing, or if it's a poor implementation of what I'm trying to accomplish, but I would like to:
understand why this is happening
retrieve the initial data once and share it between controllers
data.json
[
{"firstName":"John",
"lastName":"Denohn",
"profession":"Student",
"age":10
},
{"firstName":"Mark",
"lastName":"Fatzigio",
"profession":"Doctor",
"age":20
},
{"firstName":"Jennifer",
"lastName":"Cooler",
"profession":null,
"age":30
},
{"firstName":"Kimberly",
"lastName":"Branch",
"profession":"Teacher",
"age":40
}
]
index.html
<!DOCTYPE html>
<html lang="en" data-ng-app="myApp">
<head>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
<link href="myApp.css" rel="stylesheet">
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.min.js"></script>
<script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.10.0.js"></script>
</head>
<body>
<div data-ng-view="" data-ng-cloak ></div>
<script src="myApp.js"></script>
<script src="myAppModels.js"></script>
<script src="myAppControllers.js"></script>
</body>
</html>
template_initialPageView.html
<div class="page-container" data-ng-cloak>
<!-- Table Content -->
<table class="table" data-ng-cloak>
<thead>
<tr><th colspan="{{keysToShow.length}}"><h1>People</h1></th></tr>
<tr><th data-ng-repeat="header in keysToShow">{{ header.displayName }}</th></tr>
</thead>
<tbody>
<tr data-ng-repeat="person in people | orderBy:orderProp">
<td><a href="#{{[person.firstName, person.lastName].join('_')}}"
data-ng-click="showModal(person)"
>{{ [person.firstName, person.lastName].join(' ') }}</a></td>
<td>{{ person.profession }}</td>
</tr>
</tbody>
</table>
</div>
template_modalContentView.html
<div class="modal-header">
<button type="button" class="close" data-ng-click="cancelModal()">×</button>
<h3 class="modal-title" id="myModalLabel">Person Info</h3>
</div>
<div class="modal-body">
<tabset>
<tab heading="Age">
<h4>Name</h4>
<p>{{ person.firstName + ' ' + person.lastName }}</p>
<h4>Age</h4>
<pre>{{ person.age }}</pre>
</tab>
<tab heading="Profession">
<h4>Name</h4>
<p>{{ person.firstName + ' ' + person.lastName }}</p>
<h4>Profession</h4>
<pre>{{ person.profession }}</pre>
</tab>
</tabset>
</div>
<div class="modal-footer">
<button class="btn btn-primary" data-ng-click="closeModal()">Close</button>
</div>
myApp.js
var myApp = angular.module('myApp', ['ui.bootstrap', 'ngRoute']);
/* Routes */
myApp.config(function($routeProvider) {
$routeProvider
.when('/home', {
templateUrl: 'template_initialPageView.html',
controller: 'PageViewController',
controllerAs: 'page'
})
.otherwise({
redirectTo: '/home'
});
});
myAppControllers.js
var myAppControllers = {};
// Define: Page View Controller
myAppControllers.PageViewController = function ($scope, $modal, modelFactory) {
init();
function init(){
$scope.orderProp = '';
$scope.keysToShow = [{'displayName':'Fullname'},{'displayName':'Profession'}];
modelFactory.getPeople().success(function(data){
$scope.people = data;
});
}
$scope.showModal = function(person) {
console.log('person clicked', person);
$scope.person = person;
var modalInstance = $modal.open({
controller: 'ModalController',
controllerAs: 'modal',
templateUrl: 'template_modalContentView.html',
resolve: {
person: function(){
return $scope.person;
}
}
});
};
};
// Define: Modal Controller
myAppControllers.ModalController = function ($scope, $modalInstance, person) {
init();
function init(){
$scope.person = person;
}
$scope.cancelModal = function (){
$modalInstance.dismiss('cancel');
};
$scope.closeModal = function () {
$modalInstance.close();
};
};
// Add controlers to the module
myApp.controller(myAppControllers);
myAppModels.js
myApp.factory('modelFactory', function($http){
var factory = {};
factory.getPeople = function (){
return $http.get('data.json');
};
return factory;
});
You can try this, it initially returns an empty array that will be populated when $http.get() returns and it re-uses the array each time it is called:
myApp.factory('modelFactory', function($http){
var factory = {};
factory.getPeople = function () {
if (typeof(factory.people) == "undefined") {
factory.people = [];
$http.get('data.json').success(function(result) {
var i = 0;
for (i = 0; i < result.length; i++) {
factory.people.push(result[i]);
}
});
}
return factory.people;
};
return factory;
});
And don't forget to change your assignment to accept an array and just use that:
$scope.people = modelFactory.getPeople();
(PLUNKR)
Related
cartController in AngularJS:
angular.module('demo', [])
.controller('Hello', function($scope, $http) {
$scope.refreshCart = function() {
$http.get('http://localhost:8080/rest/cart')
.success(function(response) {
$scope.items = response.data;
});
};
$scope.removeFromCart = function(productId) {
$http.delete('/delete/' + productId)
.success(function (data) {
$scope.refreshCart();
});
};
$scope.addToCart = function(productId) {
$http.put('/add/'+ productId)
.then(function(response) {
$scope.refreshCart();
});
};
});
First HTML file (here everything works):
<a href = "#" type="button" class="btn btn-info" th:attr="
ng-click='addToCart(' + ${product.id} + ')'" data-toggle="modal" data-target="#myModal">
Add to cart</a>
Second HTML file:
<html lang="en" xmlns:th="http://www.thymeleaf.org" ng-app="demo">
<script src="http://localhost:8080/cartController.js"></script>
<body ng-controller="Hello">
(...)
<tbody ng-repeat="item in items.cartItemList">
<div class="row">
<h4 class="nomargin">{{item.product.name}}</h4>
<p>{{item.product.description}}</p>
</div>
<td data-th="Price">{{item.price}} PLN</td>
<td data-th="Quantity">{{item.quantity}}</td>
</tbody>
(...)
So what i need to do is:
1) Hit the button in first HTML file, and load JSON to $scope.items (it works).
2) Show the second HTML file, load JSON from $scope.items, and view this JSON to user.
But when I get the second HTML file and try to show data, the $scope.items is empty. Can you help pleae ?
Do you get console errors in your browser? Maybe you have to define items on the controller as empty array like in the example below ...
.controller('Hello', function($scope, $http) {
//define empty array
$scope.items = [];
$scope.refreshCart = function() {
$http.get('http://localhost:8080/rest/cart')
.success(function(response) {
$scope.items = response.data;
});
};
//...
}
I would suggest you to use broadcast and emit. Pass data between the controllers using these. You should use $broadcast if you want to pass data from parent controller to child controller. And emit if the other way around.
ModalInstance data is getting NULL in importing controller.
I have changed modelInstance name also.But dint work out.
here am adding my code,
SaveController.js
scope.open = function (_data) { //data is present
var modalInstanceData = modal.open({
controller: "PopUpController",
templateUrl: 'myModalContent.html',
resolve: {
data: function()
{
return _data; // values are present here
}
}
});
};
PopUpController.js
angular.module('user').controller('PopUpController',
['$scope','$state','$uibModalInstance',
function(scope,state,modalInstanceData,data) {
data={};
scope.data = data;
farmBid.produceValue = scope.data.produceId; //value is present here
}])
Html
<script type="text/ng-template" id="myModalContent.html">
<div class="modal-body">
<input type="text" name="produceValue" ng-model="farmBid.produceValue" />
<!-- But here its not prefilling the data-->
<input type="submit" ng-click="generate(farmBid)">
</div>
</script>
Modal data values are not being visible in HTML page
Please help
You should pass the parameters in right order and should match, you are missing 'data'
angular.module('user').controller('PopUpController',
['$scope','$state','$uibModalInstance','data',
function(scope,state,modalInstanceData,data) {
<section ng-app="app" ng-controller="ctrl">
<div id="output">{{ foo }}</div>
<button ng-click="myFun()">Click me</button>
</section>
var app = angular.module("app", []);
app.controller('ctrl', function($scope, $http){
$scope.bar = 123;
$scope.myFun = function(){
$http.get('template.html').then(function(response){
$scope.foo = response.data;
});
};
});
//template
<h1>{{ bar }}</h1>
I'm new in angularjs
I try to create a ng-click and get a template data into page like ajax
I try to use variable inside of template
anyone know how to pass variable to template in angularjs?
I find another way to solve your question, i hope this sample helps you
<html ng-app="app" ng-controller="ctrl">
<head>
<title>sample</title>
</head>
<body>
<div ng-include="template"></div>
<button ng-click="myFun()">Click me</button>
<script src="angular.js"></script>
<script type="text/javascript">
var app = angular.module("app", []);
app.controller("ctrl",
function ($scope) {
$scope.bar = 123;
$scope.myFun = function () {
$scope.template = "temp.html";
};
});
</script>
Template
<h1>{{ bar }}</h1>
I've a module where I configure a route like this :
var app = angular.module("myModule", ['ui.grid','ui.bootstrap','ngRoute']);
app.config(function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController'
})
}
In the template page I configure the controller like this :
<script src="/Scripts/SPScripts/Services/SubjectService.js"></script>
<script src="/Scripts/SPScripts/Controllers/SubjectController.js"></script>
<div id="dvcollection" data-ng-controller="SubjectController">
<div style="padding-left: 15px; padding-bottom: 10px;">
<button type="button" id="addRow" class="btn btn-success" data-ng-click="addRow()">Nuovo</button>
</div>
<div class="gridStyle" data-ui-grid="gridOptions"></div>
</div>
In this way the controller is undefinied and seems that the scripts aren't loaded in the page correctly.
If I move the scripts in my Master Page (where I load the angular module) the controller is loaded correctly.
MasterPage :
<script src="/Scripts/SPScripts/Modules/Module.js"></script>
<div class="container body-content" data-ng-app="myModule">
<div data-ng-view></div>
</div>
I would like to load the various controllers on the pages where are needed so as not to burden the application, since they are loaded all into the master page.
**** - EDIT - ****
Seems that I can load scripts by using the 'resolve' in route :
var resolveController = function (path) {
var deferred = $q.defer();
var script = document.createElement('script');
script.src = path;
script.onload = function () {
$scope.$apply(deferred.resolve());
};
document.body.appendChild(script);
return deferred.promise;
};
app.config(function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController',
resolve: resolveController('/Scripts/SubjectController.js')
})
}
But I retrieve the error : $q is not defined.
Is it the correct way?
try this : remove data-ng-controller="SubjectController" from template
In Your Angular Module File :
var app = angular.module("myModule", ['ui.grid','ui.bootstrap','ngRoute']);
app.config([ $routeProvider , function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController'
});
}])
Then in Your Template File
<div id="dvcollection" >
<div style="padding-left: 15px; padding-bottom: 10px;">
<button type="button" id="addRow" class="btn btn-success" data-ng-click="addRow()">Nuovo</button>
</div>
<div class="gridStyle" data-ui-grid="gridOptions"></div>
</div>
In Your master Page
<script src="/Scripts/SPScripts/Modules/Module.js"></script>
<div class="container body-content" data-ng-app="myModule">
<div data-ng-view></div>
</div>
after your edit it seems you didn't 'inject' $q in your resolver :
var resolveController = function ($q,$rootscope) {
var deferred = $q.defer();
var script = document.createElement('script');
script.src = '/Scripts/SubjectController.js';
script.onload = function () {
$rootscope.$apply(deferred.resolve());
};
document.body.appendChild(script);
return deferred.promise;
};
app.config(function ($routeProvider) {
$routeProvider.when('/subjects', {
templateUrl: 'Subjects.aspx',
controller: 'SubjectsController',
resolve: { resolveController: resolveController
})
}
I've replaced $scope with $rootscope and injected it as $scope isn't defined.
Hope this help, found this question on the subject with a interesting discussion about it.
You need to do this:
$injector = angular.injector(['ng']);
q = $injector.get('$q');
var deferred = q.defer();
I'm trying to display text fields (like a form) inside a table. I got a button, when I click it one new line is added to the table and all the cells are form fields. When I click the button one new line appears (that's ok), but, the html code for the fields is showing up like text. I''ve tryed to render as html but it doesn't work:
1.Render text as html with angularJs
2.AngularJS : Insert HTML into view
3.http://fdietz.github.io/recipes-with-angular-js/common-user-interface-patterns/editing-text-in-place-using-html5-content-editable.html]
I've done an index.html which provides 3 routes to he diferent views. The index file is what contains all angular sripts and my own scripts. I'm looking for the easiest way. This is the first time I work with angular.
index.html:
<html ng-app="assets">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="sources/js/angular.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.10/angular-route.min.js"></script>
<script>
var assets = angular.module('assets', ['ngRoute']);
assets.config(function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'home.html'
}).
when('/:tipusactius', {
templateUrl: 'tipusactius.html',
controller: 'TipusActiusCtrl'
}).
when('/:tipusactius/alta', {
templateUrl: 'tipusactius-alta.html',
controller: 'AfegirTipusActiusCtrl'
}).
otherwise({
redirectTo: '/'
});
});
assets.controller('TipusActiusCtrl', function ($scope, $http){
$http.get('http://10.0.203.73/WS/ws.php/tipusactius/').success(function(data) {
$scope.tipus_actius = data;
});
// Ordena taula per id desc
$scope.sortField = 'idtipus_actius';
$scope.reverse = false;
});
assets.controller('AfegirTipusActiusCtrl', function ($scope, $http, $sce){
$scope.renderHTML = "<input type='text' name='firstname'>";
// Camps formulari text pla
$scope.nomAtribut = "<input type='text' name='firstname'>";
$scope.tipus = "<input type='text' name='firstname'>";
$scope.mida = "<input type='text' name='firstname'>";
$scope.prioritat = "<input type='text' name='firstname'>";
$scope.obligatori = "<input type='text' name='firstname'>";
$scope.atributs = [];
$scope.addField = function() {
$scope.atributs.push($scope.atributs.length);
};
});
</script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"
integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
</head>
<body>
<div class="container" ng-view></div>
</body>
</html>
tipusactius-alta.html:
<script>
</script>
<div class="row">
<div class="col-md-8" ng-controller="AfegirTipusActiusCtrl">
<button ng-click="addField()">Nou atribut</button>
<div class="col-md-8">
<table class="table">
<tr>
<td>Nom atribut</td>
<td>Tipus</td>
<td>Mida</td>
<td>Prioritat</td>
<td>Obligatori</td>
</tr>
<tr ng-repeat="atribut in atributs">
<td>{{nomAtribut}}</td>
<td>{{tipus}}</td>
<td>{{mida}}</td>
<td>{{prioritat}}</td>
<td>{{obligatori}}</td>
</tr>
</table>
</div>
</div>
</div>
</div>
I wasted all my morning with this thing. This is the code without the Html render tests. Any help will be helpful.
Solved:
Finally I did it like #Ankh told me:
The text needs to be compiled as html by Angular for it to render
properly. Try creating a 'compile' directive. That will call $compile
on any text passed into it..
assets.directive('compile', compile);
function compile($compile)
{
return {
restrict: 'A',
replace: true,
link: linkFunction
};
function linkFunction(scope, element, attrs)
{
scope.$watch(
function (scope)
{
return scope.$eval(attrs.compile);
},
function (value)
{
element.html(value);
$compile(element.contents())(scope);
}
);
}
} .. and in your template
<tr ng-repeat="atribut in atributs">
<td compile="nomAtribut"></td>
<td compile="tipus"></td>
<td compile="mida"></td>
<td compile="prioritat"></td>
<td compile="obligatori"></td>
</tr>
The text needs to be compiled as html by Angular for it to render properly. Try creating a 'compile' directive. That will call $compile on any text passed into it..
assets.directive('compile', compile);
function compile($compile)
{
return {
restrict: 'A',
replace: true,
link: linkFunction
};
function linkFunction(scope, element, attrs)
{
scope.$watch(
function (scope)
{
return scope.$eval(attrs.compile);
},
function (value)
{
element.html(value);
$compile(element.contents())(scope);
}
);
}
}
.. and in your template
<tr ng-repeat="atribut in atributs">
<td compile="nomAtribut"></td>
<td compile="tipus"></td>
<td compile="mida"></td>
<td compile="prioritat"></td>
<td compile="obligatori"></td>
</tr>