I'm facing a problem with an undefined function in AngularJs and I didn't find any fitting solution on the internet:
I try to build a single page website. A few tabs are nested in the index.html with ng-include.
If i open the tab1.html allone the angular-functions work as expected.
But if i open the index.html (with the embedded tab1.html) the function is undefined and the angular function dosn't work anaymore.
I would be very thankful if someone could help me!!!
-code below-
index.html
<!--Tab-Container-->
<div lang="en" ng-app="IndexPage" ng-cloak class="tabsdemoDynamicHeight" ng-cloak="">
<md-content>
<md-tabs md-dynamic-height="" md-border-bottom="">
<!-- Content TAB 1 -->
<md-tab label="Tab1">
<md-content class="md-padding">
<div ng-include src="'views/tab1.html'"></div>
</md-content>
</md-tab>
<!-- Content TAB 2 -->
...
</md-tabs>
</md-content>
</div>
<script type="text/javascript">angular.module('IndexPage', ['ngMaterial']);</script>
index.js
angular.module('IndexPage',['ngMaterial', 'ngMessages', 'material.svgAssetsCache']);
tab1.html
<body>
<div ng-app="tableapp" ng-controller="Ctrl" >
{{ user.name || "empty" }}
</div>
</body>
tab1.js
var tableapp = angular.module("tableapp", ["xeditable"]);
tableapp.run(function(editableOptions) {
editableOptions.theme = 'bs3'; // bootstrap3 theme. Can be also 'bs2', 'default'
});
tableapp.controller('Ctrl', function($scope) {
$scope.user = {
name: 'awesome user'
};
});
You can't define an ng-app inside an ng-app, and you definitely can't have multiple <body> tags on the same html page, and this is exacltly what happends when angular injects tab1.html template into your index.html.
If tab1.html is just a view inside your main app, it can't be in the form of
<body>
<div ng-app="tableapp" ng-controller="Ctrl" >
{{ user.name || "empty" }}
</div>
</body>
But more like:
<div>
<div ng-controller="Ctrl" >
{{ user.name || "empty" }}
</div>
</div>
And of course inject the tableapp module to your main IndexPage module.
Related
I am new in angular js, I am trying to format a json data with angular js.
Here is my json data
[
{"field_add_link": "Home"},
{"field_add_link": "About Us"}
]
here is my conroller
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController',function($scope, $http) {
$http.get('http://localhost/drupal3/menu')
.then(function(response) {
$scope.links = response;
});
});
and finally here is how i am fetching the json data with angular
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links" ng-bind-html="links">
<p>{{ link.field_add_link }}</p>
</div>
</div>
no output was shown after this, giving an error Error: [$sce:unsafe] Attempting to use an unsafe value in a safe context. in the browser's console
but when I used ng-bind-html="links[0].field_add_link instead of ng-bind-html="links" and <p>{{ link[0].field_add_link }}</p> instead of <p>{{ link.field_add_link }}</p>
then i get Home as output 'without interpreting the tag'
Pls, how do I go about this?
First of all you dont need the ng-bind-html attribute on your div with ng-repeat. It should be on your p tag. Second, you need to bind link (the current element of the ng-repeat-loop) not links (the array). Although you need to look into the error [$sce:unsafe]. HTMl can only be bind to an element-body if it is trusted. For that you need to have, for example, a filter.
myApp.filter ('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml (text);
};
}]);
<div class="col-md-8 content" ng-controller ="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link | to_trusted"></p>
</div>
</div>
You just need to move your ng-bind-html from div to <p> like following code.
<p ng-bind-html="link.field_add_link"></p>
var myApp = angular.module('myApp', ['ngSanitize']);
myApp.controller('myController', function($scope, $http) {
var data = [{"field_add_link": "Home"},
{"field_add_link": "About Us"}];
$scope.links = data;
//For demo, removed the http call
});
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-sanitize.js"></script>
</head>
<body ng-app="myApp">
<div class="col-md-8 content" ng-controller="myController">
<div class="col-md-12" ng-repeat="link in links">
<p ng-bind-html="link.field_add_link"></p>
</div>
</div>
</body>
Web project: backend - ASP.NET, frontend - AngularJS.
I have the "main page" with mainApp module.
Also i have the another page with the registration, which is the responsibility of LoginLayerApp.
What i want: when you click on "main window" i need pop-up window with the registration content (html, css, angularController and so on).
What was tried:
Loaded using JQuery, implement the DOM and call angular.bootstrap by
hands.
Loaded via $http and using ngDialog library to open a pop-up
window.
Use the iframe.
The problem is that the loaded naked HTML, but I do not know how to inject LoginLayerApp, to then rebuild the naked HTML. I can do it only once, but not as usual, when angular always rebuild view by changes in controller (for example, different ng-class depending on the width of the screen).
How to do the most right? Perhaps I should do differently to organize something?
RequireJS, WebPack will not work, too much legacy-project implementation for such a trifle.
Example of registration page:
#using Inventum.ViewModels.Account
#using Microsoft.Owin.Security
#{
Layout = null;
}
<link href="~/Content/css/layers/Login/loginRegistrationLayer.min.css" rel="stylesheet" />
<div ng-app="loginLayerApp"
ng-controller="loginLayerController as loginCtrl"
ng-init="init(); returnUrl = '#ViewBag.ReturnUrl'; type = ('#ViewBag.Type' == '') ? 'login' : '#ViewBag.Type'; form={}; user={};"
esc-key="closeLayer()"
class="login-app-container"
tabindex="0">
<div class="container" ng-class="{'mobile': !desktop, 'desktop': desktop }" ng-switch on="type">
<!-- =============== LOGIN =============== -->
<div class="registration-container" ng-switch-when="login">
{{loginCtrl.desktop}}
{{desktop}}
<h1>#Html.ClickZone("NewRegLogin.Login.Title")</h1>
<div class="main-label">
<span>#Html.ClickZone("NewRegLogin.Login.HelpLabel")</span>
<br ng-show="phoneBreakpoint">
</div>
<!-- ======== Errors block ======== -->
<!-- ======== Errors block ======== -->
<div class="options">
<ng-form name="form.userForm" ng-class="{'showMe': nosocial && !desktop}" novalidate enter-key="trySubmit = true; submitForm(form.userForm.$valid, user)">
<!-- <form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate> -->
<div class="emailFocusHandler" ng-hide="desktop || nosocial" ng-click="nosocial = true;"></div>
<div class="group">
</div>
<div ng-show="desktop || nosocial">
<div class="group">
</div>
<div class="help-buttons">
</div>
<div class="error-block" ng-if="loginFailed && answerCode == ANSWERS.LOGIN.UserNoutFound">
</div>
<button type="submit" ng-click="trySubmit = true; submitForm(form.userForm.$valid, user)">#Html.ClickZone("NewRegLogin.SignIn") </button>
</div>
</ng-form>
<div class="delimeter" ng-show="desktop || nosocial"></div>
</div>
</div>
<!-- =============== LOGIN =============== -->
</div>
#section scripts {
<!-- ANGULARJS -->
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-route.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-messages.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular-animate.min.js"></script>
#Scripts.Render("~/bundles/js/layer/newLogin")
<script src="https://www.google.com/recaptcha/api.js?onload=vcRecaptchaApiLoaded&render=explicit" async defer></script>
}
What I would do is create the modal window (pop-up window) as a angular-ui modal. (their modal docs). That way you don't have to write your own modal code.
When you implement it, the modal will get its own controller and its own html file and the implementation will look like this:
Current Controller-
appName.controller('loginLayerController', ["$scope","uibModal", function ($scope, $uibModal){
$scope.openComponentModal = function () {
var modalInstance = $uibModal.open({
templateUrl: 'myModalContent.html',
controller: 'myModalController',
controllerAs: 'myModalController'
}
});
}])
And from there you can put your form into myModalContent.html, and hide and show buttons there accordingly
I'm not sure, but you can try to create component, that will show your errors. By default set in invisible. In controllers you can manage how many and when you should show your error messages.
As per the AngularJS article (have a look in nested controller fragment), I'm trying to implement nested controllers with ng-include
index.html
<body id="spaWrapperApp" ng-app="spaWrapperApp">
<div class="container-fluid" id="wrapper" ng-controller="mainController">
<div class="navigation">
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f1.html')">
<span>Page 1</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f2.html')">
<span>Page 2</span>
</a>
<a href="javascript:void(0);" ng-click="requestPage('sample3_nestedApps_f3.html')">
<span>Page 3</span>
</a>
</div>
<div id="content" >
<div ng-include="currentPage"></div>
</div>
</div>
<script type="text/javascript">
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
console.log($scope);
$scope.requestPage = function(friendlyURL){
console.log(friendlyURL);
$scope.currentPage = friendlyURL;
}
}]);
</script>
</body>
Page1 (code given below)file will injected in ng-include
<div>Testing page include 1</div>
<hr/>
<br/>
<div ng-controller="FirstController">
<p>1# {{ name }}</p>
<div ng-controller="SecondController">
<p>2# {{ name }}</p>
</div>
</div>
<script type="text/javascript">
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);
</script>
In the whole case the end result will be nested controller injected in ng-include area.
The issue is when I run that code that time this error is shown to me.
"Error: [ng:areq] Argument 'FirstController' is not a function, got undefined"
Any idea what exactly going wrong ?
Something unexpected going in AngularJS.
If you are using ng-include and try to inject pageX in that area and pageX contains some script, in that case pageX script not executed, for that I just write all the angularJS controllers handler in index.html only and it works fine for me.
like
window.spaWrapperApp = angular.module('spaWrapperApp',[]);
spaWrapperApp.controller('mainController',['$scope',function($scope){
$scope.currentPage = "sample3_nestedApps_f1.html";
$scope.requestPage = function(friendlyURL){
$scope.currentPage = friendlyURL;
}
}]);
spaWrapperApp.controller('FirstController',['$scope',function($scope){
$scope.name = "FirstController Name";
}]);
spaWrapperApp.controller('SecondController',['$scope',function($scope){
$scope.name = "SecondController Name";
}]);
I am building a quick Angular app that uses a service to grab a JSON from a URL.
The JSON structure looks like this:
{news:[{title:"title",description:'decription'},
{title:"title",description:'decription'},
{title:"title",description:'decription'}
]};
What I need is just the array within the news object.
My code to import the JSON is as follows:
app.factory('getNews', ['$http', function($http) {
return $http.get('URL')
.success(function(data) {
return data;
})
.error(function(err) {
return err;
});
}]);
Then to add the data to the $scope object in the controller I do this:
app.controller('MainController', ['$scope','getNews', function($scope, getNews) {
getNews.success(function(data)) {
$scope.newsInfo = data.news;
});
});
But it doesn't work. When I load the html page, there is only white. My thinking is that this is because it isn't grabbing the array within the JSON and using that data to populate the HTML directive I set up.
newsInfo.js:
app.directive('newsInfo',function(){
return {
restrict: 'E',
scope: {
info: '='
},
templateUrl:'newsInfo.html'
};
});
newsInfo.html:
<h2>{{ info.title }}</h2>
<p>{{ info.published }}</p>
My HTML doc is:
<head>
<title></title>
<!--src for AngularJS library-->
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>
</head>
<body ng-app="THE APP NAME"> <!--insert ng app here-->
<div ng-controller="MainController"> <!--insert ng controller here-->
<div ng-repeat="news in newsInfo"><!--insert ng repeat here-->
<!-- directive goes here-->
<newsInfo info="news"></newsInfo>
</div>
</div>
<!-- Modules -->
<script src="app.js"></script>
<!-- Controllers -->
<script src="MainController.js"></script>
<!-- Services -->
<script src="getNews.js"></script>
<!-- Directives -->
<script src="newsInfo.js"></script>
</body>
Thoughts?
Change
<newsInfo info="news"></newsInfo>
to
<news-info info="news"></news-info>
example: https://jsfiddle.net/bhv0zvhw/3/
You haven't specified the controller.
<div ng-controller="MainController"> <!--insert ng controller here-->
<div ng-repeat="news in newsInfo"><!--insert ng repeat here-->
<!-- directive goes here-->
<newsInfo info="news"></newsInfo>
</div>
</div>
$scope.getNews = function(){
return $http.get('URL').success(function(data) {
return data.news;
})
};
^ This, just change it so that the success function returns only the news!
While I am answering my own question, I should point out that everyone's answers were also correct. The code had multiple errors, but the final error was fixed by doing the following:
Apparently I had to upload the newsInfo.html doc to an S3 bucket and use that URL as “Cross origin requests are only supported for HTTP.” But then Angular blocked that external source with the Error: "$sce:insecurl Processing of a Resource from Untrusted Source Blocked".
So since the html template was so simple, i just bipassed this issue by typing in the template directly into the .js directive and it worked! thanks everyone for the help!
From couple of days I'm working on angularjs app. After 2 days of brain storming now I got to know how to use angularjs's new router+components+ng-outlet stuff.
Now, after moment of happiness one more strange problem came up. That is - In my app mainly 2 kind of pages are there.
Landing page (where I need only 1 ng-outlet)
Other pages (where I need 3 ng-outlet. It's like top navigation bar, side bar & main content area. See below screenshot )
So what i want, when user will move from landing page to some other page how i create dynamically 3 ng-outlet in my index.html file. So that, I can populate my top navigation bar component, side bar component & main content area.
Any clue, how to do handle such kind of situations ?
Thanks & Regards
index.html code
<body layout="column" ng-controller="AppCtrl">
<div ng-outlet="navigation" id="navigation">
</div>
<div layout="row" flex>
<md-sidenav layout="column" class="md-sidenav-left md-whiteframe-z2" md-component-id="left" md-is-locked-open="$mdMedia('gt-sm')">
<div ng-outlet="sidebar">
</div>
</md-sidenav>
<div layout="column" flex id="content">
<md-content layout="column" flex class="md-padding">
<div ng-outlet="main">
</div>
</md-content>
</div>
</div>
<script src="bower_components/angular/angular.min.js"></script>
<script src="bower_components/angular-animate/angular-animate.min.js"></script>
<script src="bower_components/angular-aria/angular-aria.min.js"></script>
<script src="bower_components/angular-material/angular-material.min.js"></script>
<script type="text/javascript" src="assets/js/router.es5.js"></script>
<script type="text/javascript" src="assets/js/app.js"></script>
</body>
I was facing the same issue, my workaround was to create a void component, with an empty controller and this template: "<div style='display:hidden;'></div>"
So, whenever i want to make a component "disappear" I assign it the void component, like this:
function appController($router) {
$router.config([
{ path: '/', redirectTo: '/splash' },
{ path: '/splash', components: { left: 'void', main: 'splash' } },
{ path: '/left', components: { main: 'splash', left: 'left' } }
]);
}
Hope it helps,
Renato