I created an Angular app that uses Bootstrap. I based the project on a template that I downloaded and studied. I downloaded it from here: https://angularstart.codeplex.com
I did not use or modify the template to create the project that I have now. Instead, I created a new project and used Nuget to download the latest packages for Angular & Bootstrap.
The problem is in my 'Contact' page, which has a form for site visitors to send me a message. I have defined a function - sendMessage - inside the controller which is bound by ng-click to a button in the HTML.
appRoot.controller('ContactController', ['$scope', '$http', function ($scope, $http) {
$scope.contactModel = {};
$scope.sendMessage = function () {
alert('msg: ' + $scope.contactModel.msgSubject);
}
}]);
<input type="text" id="msgSubject" name="msgSubject" data-ng-model="contactModel.msgSubject" />
<button class="btn btn-primary" ng-click="sendMessage()" >Send Message</button>
The button and click event works fine but inside the function, it cant access the model variable. It returns with an 'undefined' - the alert says "msg: undefined"
I've researched this for three days now. I've looked at other demo code on plunkr and jsfiddle and I've seen it work but something in my setup prevents access to the scope variables (basically my defined model vars).
My angular app.js is:
var appRoot = angular.module('main', ['ngRoute', 'ngResource']);
appRoot
.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', { templateUrl: '/main/home', controller: 'HomeController' })
.when('/home', { templateUrl: '/main/home', controller: 'HomeController' })
.when('/contact', { templateUrl: '/main/contact', controller: 'ContactController' })
}])
.controller('RootController', ['$scope', '$route', '$routeParams', '$location', function ($scope, $route, $routeParams, $location) {
$scope.$on('$routeChangeSuccess', function (e, current, previous) {
$scope.activeViewPath = $location.path();
});
}]);
I've tested adding the variable when initializing the contactModel variable:
$scope.contactModel = { msgSubject: 'tst sub' };
The alert inside the 'sendMessage' function sees this and shows "msg: tst sub" correctly.
I've tried different configurations for the ContactController, including passing $location and $resource like so:
appRoot.controller('ContactController', function ($scope, $location, $resource) {
}
but still can't access the scope variables.
In all the samples & demos I've checked out - including the Angular Start tempate - the controller can access the defined ng-model variable. Makes me think it has to be in my configuration or use of the differnt versions of either Angular or Bootstrap.
My _Layout.cshtml defines the default controller and ng-app as so:
<body data-ng-app="main" data-ng-controller="RootController"style="background-color:transparent;" >
Angular version is v1.2.2 and Bootstrap is v3.1.0
Any help is apporeciated. Thanks
I think I've narrowed it down. I'd like to add that I am also using ASP.NET MVC with Razor.
If I put the HTML code outside the #RenderBody() and I put the javascript alert inside the RootController, the code works:
<div >
<div>
<input type="text" id="msgSubject" name="msgSubject" data-ng-model="contactModel.msgSubject" />
<button class="btn btn-primary" ng-click="sendMessage()" >Send Message</button>
</div>
</div>
<div >
#RenderBody()
</div>
And the Javascript:
app.controller('RootController', ['$scope', '$route', '$routeParams', '$location', function ($scope, $route, $routeParams, $location) {
$scope.$on('$routeChangeSuccess', function (e, current, previous) {
$scope.activeViewPath = $location.path();
});
$scope.contactModel = {};
$scope.sendMessage = function () {
alert('msg: ' + $scope.contactModel.msgSubject);
}
}]);
If the HTML is inside the partial view (cshtml), the Angular controller does not see the scope variable as defined by ng-model.
Perhaps Angular execution is blocked by ASP.NET MVC's Razor engine? Something's going on in the #RenderBody() that is probably stripping the functionality out..
Related
I've read similar questions/answers on SO, but can't resolve my problem.
Here is the setup:
index.html
<li ng-repeat="a in article">
<a ng-click="articleDetails(a.id)">
{{a.title_en}}
</a>
</li>
js file
angular.module('myApp.article', ['ngRoute'])
.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.when('/article/:id', {
templateUrl: 'article/article.html',
controller: 'ArticleDetailCtrl'
});
//$locationProvider.html5Mode(true);
}])
.controller('ArticleDetailCtrl', ['$http', '$routeParams', '$scope', '$window', '$location',
function ($http, $routeParams, $scope, $window, $location) {
$scope.params = 'blabla';
}])
article.html
<div>{{params}}</div>
Question: When I click the link in index.html new tab is opened as expected with correct url, however, instead of article details I get Not found on the webpage. What might be a problem?
EDIT 1: Function articleDetail is defined as follows in another controller that is used in index.html:
$scope.articleDetails = function (id) {
$scope.id = id;
$scope.window = $window.open('article/' + id, '_blank');
}
You cannot retain the scope of your Angular application in another window. Hence calling $window.open will open a new window which does not have your original $scope.
The scope is tied only to the window in which the ngApp is initialized.
In order to overcome this, you can use the LocalStorage of your browser.
EDIT: Please refer this
I have an index page wherein I define two controllers. I want to call one main controller always (should be rendered always) and the other is called only for specific sub URL calls. Should I make one nested within another, or I can keep them independent of each other? I don't have access to change routes or anything, only the controller.
Right now when I use the template (HTML) mentioned, it calls/renders both controllers, even though url is say /index
Only for /index/subPage, I want both controllers to be rendering.
/index
/index/subPage
HTML:
<div ng-controller="MainCtl" ng-init=initMain()>
<p> Within ctller2 {{results}} </p>
</div>
<div ng-controller="Ctller2"> <!-- should not be displayed unless /subPage/mainUrl is rendering -->
<p> Within ctller2 {{results}} </p>
</div>
JS:
app.controller('MainCtl', ['$scope', '$http', '$location', function ($scope, $http, $location) {
$http.get('xx/mainUrl').then(function(data) {
$scope.results = someDataJSON;
console.log(someDataJSON);
});
$scope.initMain = function() {
$scope.initMethods();
}
}]);
app.controller('Ctller2', ['$scope', '$http', '$location', function ($scope, $http, $location) {
// This controller gets initialized/rendered/called even when xx/mainUrl is called, and when xx/subPage/mainUrl is called too..
$http.get('xx/subPage/mainUrl').then(function(data) {
$scope.results = someDataJSON;
console.log(someDataJSON);
})
$http.get('xx/subPage').then(function(data) {
$scope.results = data.data;
console.log(data);
})
angular.element(document).ready(function () {
alert('Hello from SubCtl, moving over from main controller to here');
});
}]);
What am I doing wrong? I'm new to Angular.js
You can conditionally initiate a controller using ng-if. So you could try something like this:
<body ng-controller="MainCtrl">
<div ng-controller="ctrl1">{{hello}}</div>
<div ng-controller="ctrl2" ng-if="showCtrl2">{{hello}}</div>
</body>
and then set the value of the variable in a parent controller by checking the current url using $location.path()
var app = angular.module('plunker', []);
app.config(function($locationProvider){
$locationProvider.html5Mode(true);
});
app.controller('MainCtrl', function($scope, $location) {
$scope.showCtrl2 = ($location.path() === 'my path');
});
app.controller('ctrl1', function($scope){
$scope.hello = 'ctrl1 says hello';
});
app.controller('ctrl2', function($scope){
$scope.hello = 'ctrl2 says hello';
});
But it's a bit hacky and for a larger project a more robust solution would require using something like ui.router.
Here i will add the product data from response of http for myctrl then when i click on checkout i have to bind all this information and send it to another jsp page in that page i have to get the response data.How can i achieve it by using angularjs. please help me out
<div ng-app="MyApp" ng-controller="MyCtrl">
<div ng-repeat="x in names">
<div>Product Name : {{x.itemname}}</div>
<div>Qty : {{x.itemQty}}</div>
<div>Price : {{x.itemQty}}</div>
<div>Total : {{x.itemQty}}</div>
</div>
<div><button ng-click="checkOut()" >CheckOut</button></div>
</div>
<script>
angular.module("MyApp",[])
.controller("MyCtrl", ['$scope', '$http', function($scope, $http) {
$http.get('responseData.html').success(function(response) {
$scope.names= response;
});
}]);
</script>
Whenever you want to persist the any object/value on client side, I'd suggest you to don't redirect the user to other page.
Instead do create a SPA, add route based view to your application. For implementing such a powerful SAP you could use angular-route API designed by angular team OR you could also use ui.router which is developed by angular-ui team. Suppose you choose angular-route here then, show different view on different routes, you need to configure you route in angular config phase using $routeProvider & then load view and controller for partial view. In your case it would be confirmation submit page on click of button.
You could have one wrapper div on your ng-view directive and then give mainCtrl controller to it. That will act as a sharing component amongest your various views.
HTML
Controller
var app = angular.module('app', ['ngRoute']);
app.config(function($routeProvider) {
$routeProvider
.when('/view1', {
templateUrl: 'view1.html',
controller: 'CustomerDetailsController'
})
.when('/view2', {
templateUrl: 'view2.html',
controller: 'form2Ctrl'
})
.otherwise({
redirectTo: '/view1'
});
});
app.controller('mainCtrl', function($scope) {
$scope.form = {}; //this is global and thats why it can be available on any view
});
app.controller('CustomerDetailsController', function($scope,$location) {
$scope.submit = function(){
if($scope.form1.$valid)
$location.path('/view2');
};
});
app.controller('form2Ctrl', function($scope,$location) {
//this controller contain the data which will you get from
});
Preferable approach for sharing a data would be using singleton service/factory in your application.
HTML
<div class="forms">
<ng-view></ng-view>
</div>
app.service('sharedData', function() {
var sharedData = this;
sharedData.myData = {};
});
app.controller('CustomerDetailsController', function($scope,$location, sharedData) {
$scope.submit = function(){
sharedData.myData.formData = $scope.form1Data; //form1Data will have form1Data
if($scope.form1.$valid)
$location.path('/view2');
};
});
app.controller('form2Ctrl', function($scope,$location, sharedData) {
console.log(sharedData); //this will have the data shared from the CustomerDetailsController
});
For more info Refer this SO Question, Thanks.
I am a novice with angular so bare with will I try and articulate what I am trying to achieve.
I have two web pages; a main 'login' page and a secondary 'about' page. The about page is nothing more than a page with HTML text. I access both pages simply with a link using ng-href.
I have a service which remembers some user login details which seem to persist when I click to the about page and then back to main.
However, I have no idea how to call a function when the user clicks back to the main page. This function would be the login function within the Main Controllers scope. I would then use the users details in the service to automatically login them in and display the users information.
This thread seems quite similar, but the user seems to be at a more advanced stage than me.
Main.html
<div class="main">
<div class="content" ng-hide="login">
<form>
... login fields ...
<button ng-click="$login()">Log in</button>
</form>
</div>
<div class="content" ng-show="login">
<form>
... user info ...
</form>
</div>
<div class="footer">
<a ng-href="#/about"/>About</a>
</div>
</div>
About.hml
<div class="about">
<div class="content">
... plain HTML ...
</div>
<div class="footer">
<a ng-href='#/main'/>mAIN</a>
</div>
</div>
app.js
'
use strict';
angular.module('sguAppApp', [
'ngResource',
'ngSanitize',
'ngRoute',
'ngAnimate'
])
.constant( 'eURL', '....webpage...' )
.config(function ($routeProvider) {
$routeProvider
.when('/main', {
templateUrl: 'views/main.html',
controller: 'MainCtrl'
})
.when('/about', {
templateUrl: 'views/about.html',
controller: 'AboutCtrl'
})
.otherwise({
redirectTo: '/main'
});
});
main.js
angular.module('App')
.service('TestService', function() {
var TestService = {};
TestService.testVar1 = '';
TestService.testVar2 = '';
TestService.testVar3 = ''
return TestService;
})
.controller('MainCtrl', function ($scope, $rootScope, .... TestService) {
$scope.user = {};
$scope.user.logon = '';
$scope.user.password = '';
$scope.sData = '';
$scope.$login = function () {
$scope.loading = true;
... do stuff to testVarNs ...
}
}
.controller('AboutCtrl', function ($rootScope, $scope, TestService) {
... somehow call $login function in MainCtrl using the testVarNs in the service ...
(not sure if this is even needed)
})
The way you laid things out, either you are in the context of MainCtrl or AboutCtrl, when you navigate from one page to the other, the existing context gets destroyed and the destination one gets instanciated.
The login function should probably live in a service, this way you can call it from wherever you like.
In that way you shold inject your TestService in the controller and call the function in response to a click for example, with ng-click="TestService.$login()"
An alternative approach could be to have another controller that is in a context that wraps your MainCtrl or AboutCtrl, Say an AppCtrl that you define early in your html file, for example:
< body ng-controller="AppCtrl'>...
now, properties defined in the AppCtrl Context are visible inside the child contexts, so if you have a $login function defined there you can call it.
I have an angular CRUD app with a list of subjects. I can add, delete and edit the subjects. My problem is that when I add or delete a subject, the page does not refresh with the new list of subjects. I've tried including $route.reload(); but it gives me a console error:
ReferenceError: $route is not defined
Can anyone advise how to fix this error or a better way of refreshing the page?
HTML:
<h3>Add a Subject</h3>
<div ng-controller="SubjectNewCtrl">
<div class = "input-group">
<form name="newSubjectForm">
Name: <br /> <input type="text" name="name" ng-model="subjects.name">
<br />
<button type="button" class="btn btn-default"><span class="glyphicon glyphicon-arrow-left"></button>
<a ng-click="createNewSubject()" class="btn btn-small btn-primary">Save Changes</a>
</form>
</div>
</div>
SubjectNewCtrl:
angular.module('myApp.controllers')
.controller('SubjectNewCtrl', ['$scope', 'SubjectsFactory', '$location',
function ($scope, SubjectsFactory, $location) {
// callback for ng-click 'createNewSubject':
$scope.createNewSubject = function () {
SubjectsFactory.create($scope.subjects);
$location.path('/subjects');
//This gives the console error
$route.reload();
}
$scope.subjects = SubjectsFactory.query();
}]);
EDIT- my routing in app.js
'use strict'
angular.module('myApp',
[
'ngRoute',
'ngResource',
'myApp.services',
'myApp.directives',
'myApp.controllers',
]);
angular.module('myApp')
.config(['$routeProvider', function($routeProvider) {
$routeProvider.
when('/subjects', {templateUrl: 'partials/subjects/subject-list.html', controller: 'SubjectCtrl'}).
when('/subjects/new', {templateUrl: 'partials/subjects/subject-new.html', controller: 'SubjectNewCtrl'}).
when('/subjects/:subjectid', {templateUrl: 'partials/subjects/subject-detail.html', controller: 'SubjectEditCtrl'}).
otherwise({redirectTo: '/home'});
}]);
angular.module('myApp.controllers')
.controller('SubjectNewCtrl', ['$scope', 'SubjectsFactory', '$location', '$route',
function ($scope, SubjectsFactory, $location, $route) {
// callback for ng-click 'createNewSubject':
$scope.createNewSubject = function () {
SubjectsFactory.create($scope.subjects);
$location.path('/subjects');
//This gives the console error
$route.reload();
}
$scope.subjects = SubjectsFactory.query();
}]);
I add "$route" to your function
try to use location.reload();
example
vm.deleteUser = function (id) {
dataService.deletUser(id)
.then(function () {
location.reload();
});
};
use scope.$apply when updating the list of subjects do not force the whole page to reload...
$scope.createNewSubject = function() {
$scope.$apply(function() {
SubjectsFactory.create($scope.subjects);
});
};
btw. $location.path('/subjects') doesn't do anything if you are already on that page
You might want to try something like this instead of reloading the route:
$scope.createNewSubject = function () {
SubjectsFactory.create($scope.subjects).then(function (newSubject) {
$scope.subjects = SubjectsFactory.query(); // [1]
});
}
This version waits until the create request has completed before refetching the list of subjects (including the new subject), which will cause the view to refresh automatically.
In your code, you're reloading the current route/view immediately after initiating the create request without giving the create request a chance to complete, so the new subject actually doesn't exist yet.
[1] Alternatively, you might prefer to do $scope.subjects.push(newSubject) instead of refetching the list of subjects.