I have an inquiry about the failure of ng-view to render a partial view in a cshtml page in a hybrid angularjs and asp.net mvc application. I have seen this work before, but cannot locate the cause of my failure.
the general scenario is to present a cshtml page which accepts input for a search and present the results on the same page while retaining the input text box for subsequent searches.
the cshtml page:
#{
ViewBag.Title = "Search";
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Search</title>
<base href="/" />
</head>
<body>
<div data-ng-app="searchModule" data-ng-controller="searchController">
<br />
<form id="search-form" data-ng-submit="searchProperty()" >
<label for="search" data-icon="">
<input id="search" type="search" data-ng-model="searchTerm" placeholder="enter title of property to find" style="width:800px; max-width:800px" />
</label>
</form>
</div>
<div>
<div ng-view="">
</div>
</div>
</body>
</html>
#section Scripts {
#Scripts.Render("~/bundles/searchBundle")
}
the angularjs controller responding to the search string submission:
searchModule.controller('searchController', function ($scope, $location, $window) {
var url = "/search/results/";
$scope.searchProperty = function()
{
//$location.path(url + $scope.searchTerm);
window.location = url + $scope.searchTerm;
}
});
searchModule.controller('searchResultsController', function($scope, $routeParams) {
$scope.searchTerm = 'test';
$scope.properties = [];
$scope.properties.push( {"id" : "1", "title": "property"});
});
the angularjs router which should handle the injection into the cshtml:
var searchModule = angular.module('searchModule', ['ngRoute']);
searchModule.config(function ($routeProvider, $locationProvider) {
$routeProvider
.when('/search/results/:searchterm',
{
templateUrl: function (params) { return '/search/results/' + params.searchterm; },
controller: 'searchResultsController', //angularjs controller; the templateUrl is an mvc reference.
})
//.otherwise({ redirectTo: '/' });
$locationProvider.html5Mode(true);
});
the relevant section of the mvc controller:
public class SearchController : Controller
{
// GET: Search
public ActionResult Index()
{
return View();
}
// GET: Search/Results/"title"
[Route("Search/Results/{SearchTerm}")]
public ActionResult Results(string SearchTerm)
{
return PartialView();
}
finally, the cshtml partial view rendering the search results. I expected this to be injected into the index.cshtml, but is actually rendered on a new page.
#{
ViewBag.Title = "Search Results";
}
<div>
<br />
<h3 class="keyword" data-ng-show="searchTerm != null">Search: {{searchTerm}}</h3>
<table>
<tbody>
<tr data-ng-repeat="property in properties">
<td>{{property.id}}</td>
<td>{{property.title}}</td>
<td><a data-ng-href="/details/{{property.id}}" data-icon="→"></a></td>
</tr>
</tbody>
</table>
</div>
the following url appears when landing on the search box page:
http://localhost:5240/Search
the following url appears after the submission on a blank page except for the bad angularjs markup which can't find the desired scope.
http://localhost:5240/search/results/333
these are both good and desirable.
I am trying to avoid having the dreaded # appear in the url.
My problem was due to lack of recognizing the true root of the navigation tree.
When I changed the navigation url as follows, the application worked as desired.
var url = "/search/#/results"; //good url
var url = "/search/results/"; //bad url
the key was that the search box page is navigated to from a main page, and is part of a spa farm, so extra attention is needed for managing navigation trees.
I am still unhappy with the hash in the url, but will address that matter as a separate query when I undertake to better understand $locationProvider.html5Mode(true);
Related
I am using angular.js as front end and node.js as backend,Now i am calling a URL which is mentioned below in button click event in my local home page.
Sample URL :
https://locahost:3000/auth/authorize?response_type=code&client_id=abzefcbbkjajsdd&scope=userfetchit&redirect_uri=localhost&nonce=32324
When i called the above URL it's shows login page in new window and after i given the email and password it's redirected to another URL which is mentioned below
Redirected URL:
https://localhost:3000/auth/localhost?code=8dacae52ee284db3dc776aa6d3563912
Expected result :
Now, i want to get the code value "8dacae52ee284db3dc776aa6d3563912" from the above URL in angular.js.
HTML code :
<html ng-app='app' ng-controller='LoginController'>
<head>
</head>
<body>
<div class="container">
<div class="jumbotron">
<button type="button"
class="btn btn-primary btn-lg" ng-click="tokenLogin()">
New Login
</button>
</div>
</div>
<pre>{{ cleanData | json}}</pre>
</body>
</html>
Controller code :
angular.module('app', [])
.controller('LoginController', ['$location','$window','$scope', '$filter', function($location,$window,$scope, $filter) {
$scope.tokenLogin = function() {
var url = 'https://localhost:3000/auth/authorize?response_type=code&client_id=abzefcbbkjajsdd&scope=userfetchit&redirect_uri=localhost&nonce=32324';
$window.open(url);
};
}]);
First of all you need to add the code parameter in your $stateProvider like this:
.state('yourstate', {
url: '/localhost?:code',
templateUrl: 'localhost.html'
});
Then in your controller you can call:
console.log($stateParams.code);
And that's it. You can set this value to scope variable or anything.
I have a method in my Web API controller returning a boolean:
[HttpGet]
public bool ValidateEmployee(string id)
{
return myRepository.VerifyEmployeeId(id);
}
and here is my UI that is calling that Web API via Angular;
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Employee ID/PIN</title>
<script src="../../Scripts/angular.js"></script>
<script src="EmployeeLoginCtrl.js"></script>
</head>
<body ng-app="myClassesApp">
<div ng-controller="myClassesController">
<form ng-submit="ValidateEmployeeId()" method="get" id="frmLogin" action="">
<input ng-model="empId" type="text" id="txtEmpId" />
<br />
<input type="submit" value="Submit" id="btnSubmit" />
<br />
<span id="lblMsg">{{EmployeeValidate}}</span>
</form>
</div>
</body>
</html>
and here is my angular controller:
(function () {
angular.module("myClassesApp", []).controller("myClassesController", EmpCtrlFunction);
EmpCtrlFunction.$inject("$scope", "$http");
function EmpCtrlFunction($scope, $http) {
$scope.ValidateEmployeeId = function () {
alert($scope.empId);
$http.get('http://localhost:49358/api/myClasses/ValidateEmployee/' + $scope.empId).
then(function (result) {
alert(result);
$scope.EmployeeValidate = result.data;
});
}
};
})();
When I enter an id and click a button, the line alert($scope.empId); gets executed and then it never gets to $http.get
What am I doing wrong?
dont use alert since alert is blocking and causes all kinds of problems in angular, use console.log instead to dump variable values and use the console tab in your browser to view output
console.log($scope.empId);
use the NET tab in your browser to view what HTTP requests are being made
The way you inject dependencies is wrong. it should be
EmpCtrlFunction.$inject = ["$scope", "$http"];
as $inject is not a function.
var loginModule = angular.module("loginModule", ['ngRoute']);
loginModule.config(['$routeProvider',
function ($routeProvider) {
$routeProvider.
when('/LoginCredential', {
templateUrl: 'login_credential.html',
controller: ''
}).
when('/SecurityQuestionPage', {
templateUrl: 'security_question.html',
controller: ''
}).
otherwise({
redirectTo: '/LoginCredential'
});
}]);
var loginCredController = loginModule.controller('loginCredController', ['$scope', '$http', function ($scope, $http) {
debugger;
$scope.loginData = {};
$scope.submit = function (LoginForm, loginData)
{
debugger;
var uname = loginData.username;
var pwd = loginData.password;
var lData = 'username='+uname+'&'+'password='+pwd
var request = $http({
method: "post",
url: "http://localhost:53738/Login?response_type=code&client_id=peopleworks&redirect_uri=google.com",
data: lData
});
request.success(
function (response) {
debugger;
}
);
}
}]);
this is login.js file. these are my views login.html and login_credential.html
login.html
<!DOCTYPE html>
<html>
<head>
<script src="Peopleworks/Scripts/angular.min.js"></script>
<script src="Peopleworks/Scripts/angular-route.min.js"></script>
<script src="Peopleworks/Lib/peopleworksLogin.js"></script>
</head>
<body>
<div data-ng-app="loginModule">
<div ng-view=""></div>
</div>
</body>
</html>
and
login_credential.html
<div data-ng-controller ="loginCredController">
<table>
<form method="post" name="LoginForm" ng-submit="submit(LoginForm, loginData)" novalidate>
<tr><td>Username</td><td><input id="username" name="username" ng-model="loginData.username" type="text" /></td>
<tr><td>Password</td><td><input id="password" name="password" ng-model="loginData.password" type="password" /></td>
<tr><td><button type="submit">Login</button>
</form>
</table>
</div>
problem is when I click submit the method in controller is not working... can anyone help me?
You have html markup wrong. Try closing tr and td tags properly and move form tag out of table tag in such a way that table reside inside form not the other way.
No need of "var loginCredController="
Simple use :-
loginModule.controller('loginCredController', ['$scope', '$http', function ($scope, $http){
...
...
}
From angularjs docs form
You can use one of the following two ways to specify what JavaScript method should be called when a form is submitted:
ngSubmit directive on the form element
ngClick directive on the first button or input field of type submit (input[type=submit])
To prevent double execution of the handler, use only one of the ngSubmit or ngClick directives.
This is because of the following form submission rules in the HTML specification:
If a form has only one input field then hitting enter in this field triggers form submit (ngSubmit)
if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter doesn't trigger submit
if a form has one or more input fields and one or more buttons or input[type=submit] then hitting enter in any of the input fields will trigger the click handler on the first button or input[type=submit] (ngClick) and a submit handler on the enclosing form (ngSubmit)
Note that ngClick events will occur before the model is updated. Use ngSubmit to have access to the updated model.
Use either ng-submit or input[type=submit].
Here is the jsfiddle.
http://jsfiddle.net/CLcfC/
code
var app = angular.module('app',['']);
app.controller('TestCtrl',function($scope){
$scope.text = 'Change Me';
$scope.$watch('text',function(){
alert('Changed !');
});
})
HTML
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="TestCtrl">
<input type="text" ng-model='text'/>
<span>{{text}}</span>
</div>
</div>
I am not able to see the change in $scope.text. Please help.
This is so easy but what am I missing?
Change the module creation to this, make sure you don't put a empty string in the []. (Obvious the empty string is not a module that can be injected.)
var app = angular.module('app', []);
Demo: http://jsfiddle.net/MWa66/
Your JavaScript file loads after the AngularJS initialization and that's why it fails to find your module. In order to fix it change the initialization to a manual initialization.
First change your HTML and remove the ng-app directive:
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
<div id="appRoot">
<div ng-controller="TestCtrl">
<input type="text" ng-model='text'/>
<span>{{text}}</span>
</div>
</div>
Then go to your JavaScript and use angular.bootstrap method to manually attach your module:
var app = angular.module('app',[]);
app.controller('TestCtrl',function($scope){
$scope.text = 'Change Me';
$scope.$watch('text',function(){
alert('Changed !');
});
});
angular.element(document).ready(function() {
angular.bootstrap(document.getElementById('appRoot'), ['app']);
});
You can find more help on manual AngularJS initialization here.
Thank you! I solved this annoying thing!
The solution that worked for me was that I use angular UI router and there I had used the following code
.state('app.monimes', {
url: "/monimes",
views: {
'menuContent' :{
templateUrl: "templates/monimes.html",
controller: 'sampleCtrl'
}
}
})
so then in the controller I had
/***
*
*Controller for tests..
*/
.controller('sampleCtrl',['$scope','sampleService', function($scope, $sampleService) {
$scope.username="em";
// Watch for changes on the username property.
// If there is a change, run the function
$scope.$watch('username', function(newUsername) {
// uses the $http service to call the GitHub API
// //log it
$scope.log(newUsername);
// and returns the resulting promise
$sampleService.events(newUsername)
.success(function(data, status, headers) {
// the success function wraps the response in data
// so we need to call data.data to fetch the raw data
$scope.events = data.data;
});
},true);
}
]);
and in the view I had
<div>
<label for="username">Type in a GitHub username</label>
<input type="text" ng-model="username" placeholder="Enter a GitHub username, like a user" />
<pre ng-show="username">{{ events }}</pre>
</div>
but that didn't work.
so I added ng-controller="sampleCtrl"
to the div and now it works :D
so that means that the view is loaded after the controller loads and the watcher doesn't get added to the watching variable.
Suppose you are using routes:
// bootstrap
myApp.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'partials/home.html',
controller: 'HomeCtrl'
});
$routeProvider.when('/about', {
templateUrl: 'partials/about.html',
controller: 'AboutCtrl'
});
...
And in your html, you want to navigate to the about page when a button is clicked. One way would be
<a href="#/about">
... but it seems ng-click would be useful here too.
Is that assumption correct? That ng-click be used instead of anchor?
If so, how would that work? IE:
<div ng-click="/about">
Routes monitor the $location service and respond to changes in URL (typically through the hash). To "activate" a route, you simply change the URL. The easiest way to do that is with anchor tags.
Go Home
Go to About
Nothing more complicated is needed. If, however, you must do this from code, the proper way is by using the $location service:
$scope.go = function ( path ) {
$location.path( path );
};
Which, for example, a button could trigger:
<button ng-click="go('/home')"></button>
Here's a great tip that nobody mentioned. In the controller that the function is within, you need to include the location provider:
app.controller('SlideController', ['$scope', '$location',function($scope, $location){
$scope.goNext = function (hash) {
$location.path(hash);
}
;]);
<!--the code to call it from within the partial:---> <div ng-click='goNext("/page2")'>next page</div>
Using a custom attribute (implemented with a directive) is perhaps the cleanest way. Here's my version, based on #Josh and #sean's suggestions.
angular.module('mymodule', [])
// Click to navigate
// similar to <a href="#/partial"> but hash is not required,
// e.g. <div click-link="/partial">
.directive('clickLink', ['$location', function($location) {
return {
link: function(scope, element, attrs) {
element.on('click', function() {
scope.$apply(function() {
$location.path(attrs.clickLink);
});
});
}
}
}]);
It has some useful features, but I'm new to Angular so there's probably room for improvement.
Remember that if you use ng-click for routing you will not be able to right-click the element and choose 'open in new tab' or ctrl clicking the link. I try to use ng-href when in comes to navigation. ng-click is better to use on buttons for operations or visual effects like collapse.
But
About
I would not recommend. If you change the route you might need to change in a lot of placed in the application. Have a method returning the link. ex:
About. This method you place in a utility
I used ng-click directive to call a function, while requesting route templateUrl, to decide which <div> has to be show or hide inside route templateUrl page or for different scenarios.
AngularJS 1.6.9
Lets see an example, when in routing page, I need either the add <div> or the edit <div>, which I control using the parent controller models $scope.addProduct and $scope.editProduct boolean.
RoutingTesting.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Testing</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular-route.min.js"></script>
<script>
var app = angular.module("MyApp", ["ngRoute"]);
app.config(function($routeProvider){
$routeProvider
.when("/TestingPage", {
templateUrl: "TestingPage.html"
});
});
app.controller("HomeController", function($scope, $location){
$scope.init = function(){
$scope.addProduct = false;
$scope.editProduct = false;
}
$scope.productOperation = function(operationType, productId){
$scope.addProduct = false;
$scope.editProduct = false;
if(operationType === "add"){
$scope.addProduct = true;
console.log("Add productOperation requested...");
}else if(operationType === "edit"){
$scope.editProduct = true;
console.log("Edit productOperation requested : " + productId);
}
//*************** VERY IMPORTANT NOTE ***************
//comment this $location.path("..."); line, when using <a> anchor tags,
//only useful when <a> below given are commented, and using <input> controls
$location.path("TestingPage");
};
});
</script>
</head>
<body ng-app="MyApp" ng-controller="HomeController">
<div ng-init="init()">
<!-- Either use <a>anchor tag or input type=button -->
<!--Add Product-->
<!--<br><br>-->
<!--Edit Product-->
<input type="button" ng-click="productOperation('add', -1)" value="Add Product"/>
<br><br>
<input type="button" ng-click="productOperation('edit', 10)" value="Edit Product"/>
<pre>addProduct : {{addProduct}}</pre>
<pre>editProduct : {{editProduct}}</pre>
<ng-view></ng-view>
</div>
</body>
</html>
TestingPage.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.productOperation{
position:fixed;
top: 50%;
left: 50%;
width:30em;
height:18em;
margin-left: -15em; /*set to a negative number 1/2 of your width*/
margin-top: -9em; /*set to a negative number 1/2 of your height*/
border: 1px solid #ccc;
background: yellow;
}
</style>
</head>
<body>
<div class="productOperation" >
<div ng-show="addProduct">
<h2 >Add Product enabled</h2>
</div>
<div ng-show="editProduct">
<h2>Edit Product enabled</h2>
</div>
</div>
</body>
</html>
both pages -
RoutingTesting.html(parent), TestingPage.html(routing page) are in the same directory,
Hope this will help someone.
Another solution but without using ng-click which still works even for other tags than <a>:
<tr [routerLink]="['/about']">
This way you can also pass parameters to your route: https://stackoverflow.com/a/40045556/838494
(This is my first day with angular. Gentle feedback is welcome)
You can use:
<a ng-href="#/about">About</a>
If you want some dynamic variable inside href you can do like this way:
<a ng-href="{{link + 123}}">Link to 123</a>
Where link is Angular scope variable.
just do it as follows
in your html write:
<button ng-click="going()">goto</button>
And in your controller, add $state as follows:
.controller('homeCTRL', function($scope, **$state**) {
$scope.going = function(){
$state.go('your route');
}
})