In my regular Javascript I append data to HTML ONLY if there's data from the server, otherwise I just show a simple div saying there's nothing. How can I implement this in AngularJS?
Example:
if (AJAXresult)
$element.append(JSONdata); //JSONdata will contain a list of customer data
else
$element.append('<div>No results</div>');
How can I achieve this in Angular?
The simplest way would be to control for the no data state in your returned view.
<div>
<div ng-if="!hasCustomers">
No Customers Available
</div>
<div ng-if="hasCustomers">
<!-- show some stuff -->
</div>
</div>
Then in your controller you can easily initialize this when you load your data:
angular.module('myApp').controller('MyController', function($scope, myDataService){
$scope.hasCustomers = false;
myDataService.getCustomers()
.then(function(value){
$scope.customers = value.data;
$scope.hasCustomers = customers && customers.length;
});
});
If you want to make sure the data is loaded before your view is ever instantiated, then you can also use the resolve property on your $route
$routeProvider.when('/someRoute/',{
templateUrl: '/sometemplate.html',
controller: 'MyController',
controllerAs: 'ctrl', // <-- Highly recommend you do this
resolve: {
customerData: function(myDataService){
return myDataService.getCustomers();
}
}
});
resolve is basically a hash of functions that return a promise, and can be dependency injected just like everything else. The controller and view will not be loaded until all the resolve promises have been fulfilled.
It will be available in your controller by the same property name you gave it:
angular.module('myApp')
.controller('MyController', function($scope, customerData){
$scope.customers = customerData;
$scope.hasCustomers = customerData && customerData.length;
});
Related
I am trying to get the inner text of a <p> element in my Angular application and pass it to a method and a view using ng-route. So when a user clicks on the <p> element, the innerText is passed through a method, gets some data back, then returns a new view with the response data returned
<p ng-click="searchUser()">Bob Ross</p>
js
var app = angular.module('app', ['ngRoute'])
.config(['$routeProvider', function($routeProvider){
.when('/searchUser:name', {
templateUrl: 'user-results.html',
controller: 'searchController'
})
app.controller('searchController', function($scope, $routeParams) {
$scope.name = $routeParams.name;
$scope.searchUser = function(){
// do some stuff;
}
});
I'm not sure how to grab the inner text of the <p> tag properly and pass it through the method (I'm likely way off); should I be binding it to my model and then passing as a routeparam?
Any help is appreciated!
I'm assuming you're using $http to get the list of users in your controller, in which case you could do this:
<p ng-repeat="user in users" ng-click="searchUser(user.name)">{{user.name}}</p>
And in your controller:
$scope.searchUser = function(userName){
// do some stuff with userName;
};
You can pass in the $event argument to the searchUser function. You can then use the $event.currentTarget to grab the element. For more details on the $event object, click here.
<p ng-click="searchUser($event)">Bob Ross</p>
$scope.searchUser = function($event){
var username = $event.currentTarget.innerHTML;
}
Nothing in my {{}} are showing in my html file. Can someone please tell me what I am doing wrong. I have no errors in my console.
"GOT DATA" will print in my console, but not show in my file.
The is my html code
<div class="announcements" ng-controller="onBusinessAnnouncementCtrl as announcements">
{{announcements.latest}}
</div>
This is my js code pulling from the server
app.controller('onBusinessAnnouncementCtrl', function($scope, $http) {
$http.get('http://localhost:3000/latest')
.success(function(responses) {
//$scope.latest = responses;
$scope.latest = "GOT DATA";
console.log($scope.latest);
});
});
Because you use the controller as syntac you should apply the variables in your controller to this instead of $scope.
See the same problem in AngularJS Ng-repeat is not working as expected where a repeater was used
below the answer on the previous question:
In your repeater you're looping over announcements.announcements in your controller you set $scope.announcements = response.
Either you change the repeater in ng-repeat="eachAnnouncement in announcements" or change your scope variable to: $scope.announcements = {announcements : response}
Figured it out! For reference:
There is nothing showing in my HTML because there is no value assigned to the controller. To assign "latest" to my controller I have to do this:
app.controller('onBusinessAnnouncementCtrl', function($scope, $http) {
$http.get('http://localhost:3000/latest')
var this = this;
.success(function(responses) {
this.latest = responses;
});
});
<div class="announcements" ng-controller="onBusinessAnnouncementCtrl as announcements">{{announcements.latest}}</div>
I have angular working in one of my ASP.NET MVC applications. I am using two html templates with Angular Routing. One is a list of current Favorites that comes from the database and is serialized into json from my Web API and used by angular to list those items from the database.
The second html template is a form that will be used to add new favorites. When the overall page that includes my angular code loads, it has a cookie named currentSearch which is holding the value of whatever the last search parameters executed by the user.
I would like to inject this value into my angular html template (newFavoriteView.html) for the value of a hidden input named and id'd searchString.
I have tried using jQuery, but had problems, plus I would much rather do this inside of angular and somehow pass the value along to my template or do the work inside the view(template). However, I know the latter would be bad form. Below is the code I think is important for one to see in order to understand what I am doing.
Index.cshtml (My ASP.NET VIEW)
#{
ViewBag.Title = "Render Search";
ViewBag.InitModule = "renderIndex";
}
<div class="medium-12 column">
<div data-ng-view=""></div>
</div>
#section ngScripts {
<script src="~/ng-modules/render-index.js"></script>
}
Setting the cookie in the MVC Controller
private void LastSearch()
{
string lastSearch = null;
if (Request.Url != null)
{
var currentSearch = Request.Url.LocalPath + "?" +
Request.QueryString;
if (Request.Cookies["currentSearch"] != null)
{
lastSearch = Request.Cookies["currentSearch"].Value;
ViewBag.LastSearch = lastSearch;
}
if (lastSearch != currentSearch)
{
var current = new HttpCookie("currentSearch", currentSearch){
Expires = DateTime.Now.AddDays(1) };
Response.Cookies.Set(current);
var previous = new HttpCookie("lastSearch", lastSearch) {
Expires = DateTime.Now.AddDays(1) };
Response.Cookies.Set(previous);
}
}
}
render-index.js
angular
.module("renderIndex", ["ngRoute"])
.config(config)
.controller("favoritesController", favoritesController)
.controller("newFavoriteController", newFavoriteController);
function config($routeProvider) {
$routeProvider
.when("/", {
templateUrl: "/ng-templates/favoritesView.html",
controller: "favoritesController",
controllerAs: "vm"
})
.when("/newsearch", {
templateUrl: "/ng-templates/newFavoriteView.html",
controller: "newFavoriteController",
controllerAs: "vm"
})
.otherwise({ redirectTo: "/" });
};
function favoritesController($http) {
var vm = this;
vm.searches = [];
vm.isBusy = true;
$http.get("/api/favorites")
.success(function (result) {
vm.searches = result;
})
.error(function () {
alert('error/failed');
})
.then(function () {
vm.isBusy = false;
});
};
function newFavoriteController($http, $window) {
var vm = this;
vm.newFavorite = {};
vm.save = function () {
$http.post("/api/favorites", vm.newFavorite)
.success(function (result) {
var newFavorite = result.data;
//TODO: merge with existing topics
alert("Thanks for your post");
})
.error(function () {
alert("Your broken, go fix yourself!");
})
.then(function () {
$window.location = "#/";
});
};
};
favoritesView.html
<div class="container">
<h3>New Favorite</h3>
<form name="newFavoriteForm" ng-submit="vm.save()">
<fieldset>
<div class="row">
<div class="medium-12 column">
<input name="searchString" id="searchString" type="hidden"
ng-model="vm.newFavorite.searchString"/>
<label for="title">Name</label><br />
<input name="title" type="text"
ng-model="vm.newFavorite.name"/>
<label for="title">Description</label><br />
<textarea name="body" rows="5" cols="30"
ng-model="vm.newTopic.description"></textarea>
</div>
<div class="medium-12 column">
<input type="submit" class="tiny button radius" value="Save"/> |
Cancel
</div>
</div>
</fieldset>
</form>
</div>
My current attepts have been using jQuery at the end of the page after Angular has loaded and grab the cookie and stuff it in the hidden value. But I was not able to get that to work. I also thought about setting the value as a javascript variable (in my c# page) and then using that variable in angular some how. AM I going about this the right way?
Or should it be handled in the angular controller?...
I'm new to angular and the Angular Scope and a bit of ignorance are getting in the way. If any other info is needed I can make it available, thanks if you can help or guide me in the right direction.
You can do it by reading the cookie value using JavaScript, set it as a property of the $scope object and access it on the template.
//Inside your controllers
function favoritesController($http, $scope) {
//Get the cookie value using Js
var cookie = document.cookie; //the value is returned as a semi-colon separated key-value string, so split the string and get the important value
//Say the cookie string returned is 'currentSearch=AngularJS'
//Split the string and extract the cookie value
cookie = cookie.split("="); //I am assuming there's only one cookie set
//make the cookie available on $scope, can be accessed in templates now
$scope.searchString = cookie[1];
}
EXTRA NOTE
In AngularJS, the scope is the glue between your application's controllers and your view. The controller and the view share this scope object. The scope is like the model of your application. Since both the controller and the view share the same scope object, it can be used to communicate between the two. The scope can contain the data and the functions that will run in the view. Take note that every controller has its own scope. The $scope object must be injected into the controller if you want to access it.
For example:
//inject $http and $scope so you can use them in the controller
function favoritesController($http, $scope) {
Whatever is stored on the scope can be accessed on the view and the value of a scope property can also be set from the view. The scope object is important for Angular's two-way data binding.
Sorry if I'm misunderstanding or over-simplifying, but...assuming JavaScript can read this cookie-value, you could just have your controller read it and assign it to a $scope variable?
If JavaScript can't read the value, then you could have your ASP write the value to a JavaScript inline script tag. This feels yuckier though.
Update to show controller-as example.
Assuming your HTML looked something vaguely like this:
<div ng-controller="MyController as controller">
<!-- other HTML goes here -->
<input name="searchString" id="searchString" type="hidden" ng-model="controller.data.currentSearch"/>
Then your controller may look something like this:
app.controller('MyController', function ($scope, $cookies) {
$scope.data = {
currentSearch: $cookies.currentSearch
};
// Note that the model is nested in a 'data' object to ensure that
// any ngIf (or similar) directives in your HTML pass by reference
// instead of value (so 2-way binding works).
});
In my angular app I have a product view/controller that has the common questions for product (SKU, Name, Description etc). I also have a dropdown field named ProductType that I will use to load a dynamic view/js/controller for questions that vary based on that product type. When the user saves the product I'll have a property on the base product model named ProductTypeConfig (as well as ProductType) that contains a json representation of the product type configuration and I want to pass all that to the server controller for persistence.
Has anyone seen this done before in Angular? Comments or clues as to how to go about this? I don't want to load all of js for every product type controller etc. ahead of time as this will potentially be plugable by the client as new product types are rolled out.
EDIT:
Ok, so I created a plunk to demonstrate what I'm trying to accomplish. I have the dynamic piece working well I think. At this point I just need to figure out how to grab the dynamic data in the saveProduct() function in the ProductController. When save is clicked, I need to somehow call a method on either the TypeAController or the TypeBController depending on which one is loaded. I was thinking that I could probably create a service that all the controllers would depend on and have it do the work. Is this something that is possible?
The plunk is located here http://plnkr.co/edit/6kQYKU
This is the main controller:
(function() {
var app = angular.module('ProductApp', ['ngRoute']);
app.config(function($httpProvider, $routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'product.html',
controller: 'ProductController'
}).
otherwise({
redirectTo: '/'
});
});
var ProductController = function($scope, $log, $routeParams, $location) {
var saveProduct = function() {
// how to get data from either TypeAController or TypeBController here when saved from ProductController
$log.log('Product saved')
$location.path('/');
};
$scope.saveProduct = saveProduct;
// values
$scope.ProductId = 1001;
$scope.Name = 'Product 1001';
$scope.Type = 'typea';
};
app.controller("ProductController", ProductController);
}());
And this is one of the dynamic views with it's controller:
<div ng-controller='TypeAController'>
<h1>Type A Settings</h1>
<fieldset>
<div class="dnnFormItem">
<label>Width:</label>
<br />
<input type="text" name="width" ng-model="Width" />
<br />
<label>Height:</label>
<br />
<input type="text" name="height" ng-model="Height" />
<br />
</div>
</fieldset>
</div>
<script>
console.log('TypeA is loaded');
var TypeAController = function($scope, $log) {
};
angular.module('ProductApp').controller("TypeAController", TypeAController);
</script>
I ended up doing a simple factory to share an object between controllers as demonstrated in this plunk, http://plnkr.co/edit/6kQYKU. This also demonstrates loading a dynamic view based on a field in the parent view.
var stateService = function() {
'use strict';
var state = {};
return {
state: state,
};
};
app.factory('StateService', stateService);
I have html page like
<div ng-controller="userListControl">
...
</div>
<div ng-controller="userDetailsControl">
....
</div>
And i have angular Js code is
var userDirectory = angular.module('userDirectory',[]);
userDirectory.controller("userListControl", ['$scope','$http', function($scope, $http)
{
$http.get('data/userData.json').success (function(data){
$scope.users = data;
$scope.users.doClick = function(user,event) {
userInfo(user);
}
});
}]);
function userInfo(users)
{
console.log(user);
userDirectory.controller("userDetailsControl", function($scope)
{
console.log('well')
$scope.user = users;
console.log($scope.user)
});
}
Here Everything is working fine. But when we are calling click event, That userInfo called with particular Data. But Second controller gives an error(angular js Error).
I am new one in angular jS. I dont know this logic is correct or not.
I have list items in first Controller. When we are clicking on list, It gets data from particular list and passed to another design. That design have detailed data. So the 2nd controller shows particular list detailed Section
First, There is no need to declare your controller inside a function - I don't think that you're trying to lazy-load controllers. Make it available to your app when it starts.
Second, you need to pass data to the userDetailsControl controller. There are various ways to do this, but here you could just use the $rootScope.
var userDirectory = angular.module('userDirectory',[]);
userDirectory.controller("userListControl", function($scope, $rootScope, $http)
{
$scope.selectUser = function(user){
$rootScope.selectedUser = user;
}
$http.get('data/userData.json')
.success (function(data){
$scope.users = data;
});
})
.controller("userDetailsControl", function($scope, $rootScope){
$rootScope.$watch("selectedUser", function(newVal){
$scope.user = newVal;
}
}
and in your HTML:
<div ng-controller="userListControl">
<button ng-repeat="user in users" ng-click="selectUser(user)">{{user.name}}</button>
</div>
<div ng-controller="userDetailsControl">
<div>{{user.name}}</div>
<div>{{user.otherDetails}}</div>
</div>