I'm retrieving a person from a service and displaying the details on the details.html template. If the person is not found, the service returns a 404 response and I handle it from within the controller by (currently) displaying an alert popup stating its not found.
Is it possible to dynamically change to a different template, like a 'notfound.html' for instance?
You can do it using ng-switch directive. Save state of your request in variable (for example $scope.items = data if you received your data correctly or $scope.items = false otherwise) and then:
<div ng-switch on="items">
<div ng-switch-when="false" ng-include src="'error.html'"></div>
<div ng-switch-default ng-include src="'details.html'"></div>
</div>
Related
I have searched through a lot of questions regarding $route.reload() and I think I still have a fundamental misunderstanding of how it and Angular are actually working. I really want to understand what is actually going on (not just a quick fix) so I apologize if this question gets rather verbose.
I am trying to create an app that will allow the user to input information into a form and then use ng-view and a controller LivePreviewController to display that form data in a "live preview" of the form which has some unique styling and other information associated with the form that the user does not input themselves.
This is very simple to do if the "live preview" is occurring on the same page as the user is inputting information using something like this
<input type="text" ng-model="form_name" />
<div ng-bind="form_name"></div>
What I would like to do is something like this.
<!--Location is: localhost:8888/form_page.html -->
<input type="text" ng-model="form_name" />
<!-- ng view is displaying the partial view: styled_form.html -->
<div ng-view></div>
Then I have another page styled_form.html which is the partial view that gets displayed by the ng-view div.
<!-- partial view page is styled_form.html -->
<div ng-bind="form_name"></div>
Both of these pages are controlled by the same controller LivePreviewController.
There are a lot of things I imagine that I am probably doing incorrectly. First thing could be the routing. I had some issues with the routing as app is only used on one page of a multi-page website my routes are setup as follows.
var previewApp = angular.module('previewApp', ['ngRoute']);
previewApp.config(['$routeProvider', function($routeProvider){
$routeProvider
.otherwise({
redirectTo:'/styled_view.html',
controller: 'LivePreviewController'
});
}]);
//Controller Code
previewApp.controller('LivePreviewController', [$scope, $route, function($scope, $route){
$scope.form_name = 'temporary name';
}]);
All of this works as expected when the form_page.html is originally loaded, but when the user changes the name in the text input the ng-view displaying my styled_form.html page is not changed. This also makes sense because the styled_form.html needs to be reloaded with the new information.
Here is where the noob starts. My first inclination was to create a refresh button and add a function in my LivePreviewController to refresh the page using $route.reload()
previewApp.controller('LivePreviewController', [$scope, $route, function($scope, $route){
$scope.form_name = 'temporary name';
$scope.refreshPage = function() {
$route.reload();
console.log($scope.form_name) //to ensure scope is updating
};
}]);
And then updated my html to include the button as follows
<!--Location is: localhost:8888/form_page.html -->
<input type="text" ng-model="form_name" />
<button ng-click="refreshPage()"> Update the Page </button>
<!-- ng view is displaying the partial view: styled_form.html -->
<div ng-view></div>
The function is working just fine when the button is clicked and the updated scope variable is displaying in the console, but my live preview is not updating. After looking through the Angular documentation I have a hunch as to what is happening. It states...
Causes $route service to reload the current route even if $location hasn't changed.
As a result of that, ngView creates new scope and re-instantiates the controller.
So if I understand the docs correctly, which I obviously don't, what is actually happening on $route.reload() is that when styled_form.html is getting reloaded the updated $scope.form_name is getting wiped out and the original $scope value is getting shown on the page. So...
Question 1: am I understanding this correctly i.e. is $route.reload() wiping out my $scope and reloading the old $scope variable, or is my $route.reload() just not reloading the page at all?
Now if I am interpreting my issue correctly my guess (seen suggested on here in other topics) is that the solution would be to create some type of service to store my data and then call that service inside of the controller. This workflow would look like
User input --> Data stored in some Service(factory) --> Data Passed to $scope --> >$scope value displayed in partial view (styled_form.html)
But I am lost as to how to dynamically store the user input inside of a service. Ideally this would all occur in realtime (as with the simple first example) as I would like to avoid having a refresh button. Could this be accomplished by creating a function in my controller that updates the values inside my service every few seconds? I need someone with better ideas than myself to point me in the right direction.
Question 2: Is this the correct workflow assuming Q1 is correct and if so what is the correct way to set up my service to handle the user input and pass it to another html page dynamically?
All help much appreciated
Having a service to store data and same controller to serve both view is fine.
Data saving could be done each time, when controller variables are changing.
When new controller is initialized, it my read the date from the service. A separate controller instance will be created for each view.
You may also check this blog to see, how data should be defined within a service, so that changing such data will auto-trigger controller to update view:
http://viralpatel.net/blogs/angularjs-service-factory-tutorial/
Notice: that service returns a reference to the array and controller saves this reference, when it is created.
Ok so I realized my problem was due to the fact that I was misunderstanding how $scope works in Angular not how $route.reload() was working. This topic
$scope variable not changing in controller when changed using directive
and this link in that question
https://github.com/angular/angular.js/wiki/Understanding-Scopes
helped me understand what I was doing wrong. $route.reload() and $templateCache.remove() were working correctly. The problem was that my $scope variable wasn't updating properly because each view was creating a different scope. Paraphrasing one of the links
The $scope is not the model.
The function of the controller is to write from the model to the scope
The function of the view is to display the $scope and write to the model if needed
I solved the problem using the controllerAS syntax discussed in the answers like this,
.controller('LivePreviewController',['$scope', function($scope) {
var vm = this;
vm.form_name = 'temporary name';
}]);
<!-- form_page.html -->
<div ng-controller="LivePreviewController as ctrl">
<input type="text" ng-model="ctrl.form_name>
And in my styled form partial view
<!-- styled_form.html -->
<div> {{ctrl.form_name}} </div>
This causes everything to work as expected
I have a MEAN stack application in which I am accessing the node backend as an API. I am able to set the response message and am also able to see it in the response object in my browser. How will I be able to access this message and display it in my HTML?
Screenshot of Network tab in browser showing the response object:
[
This is a very broad question. Really, what you've said is - "I've got the server-side, how do I do the client-side."
Anyway, you can use Angular. With Angular, you can do this:
$http.get('/items').then(function(response) {
$scope.data = response.data;
});
That gets the data to Angular(mind you, this is simplified), which can then show it in the html through templates like this:
<div ng-repeat="item in data">{{ item.name }}</div>
In your example, you're actually showing a null result. I would actually be managing the messaging for this in the Angular template something like this:
<div ng-if="!data">No items</div>
Actually, you're showing a result that appears to be an unsuccessful user lookup. For that, you'd be creating a script like this(again, this is simplified):
$http.get('/users/' + id).then(function(response) {
$scope.user = response.data.user;
});
and a template like this:
<div ng-if="user">
<h1>{{ user.name }}</h1>
<h3>Favorite Books<h3>
<div ng-repeat="book in user.books">{{ book }}</div>
</div>
<div ng-if="!user">Couldn't find user</div>
Hope this helps.
I have two controllers allocated to two views:
[ResultsView ng-controller="ResultsCtrl"]
[SearchView ng-controller="SearchCtrl"]
The Search View has many complex filters/options and is filled in by the user, then he/she can press "Search" on SearchView and Results should be populated into a Grid.
Now I can send information between two either by a Service or by using $rootScope.$broadcast.
Heres the problem I've run into:
[ResultsView ng-controller="ResultsCtrl"][SearchView ng-controller="SearchCtrl"]
[ResultsView ng-controller="ResultsCtrl"][SearchView ng-controller="SearchCtrl"]
[ResultsView ng-controller="ResultsCtrl"][SearchView ng-controller="SearchCtrl"]
If I were to have multiple Result-Search sections on the same page, how can I ensure they each act independently from each other? Using the Service approach, the ResultsCtrl and SearchCtrl both have the defined service
.controller("searchCtrl", ["$scope", "$searchHttp", function ($scope, $searchHttp) {
.controller("resultsCtrl", ["$scope", "$searchHttp", function ($scope, $searchHttp) {
So I can't change how each instance of the controller behaves regarding the service. Soon as one SearchCtrl calls the service, it will modify every ResultsCtrl instance.
Likewise using broadcasts $rootScope.$broadcast("searchResults"... will be picked up by every ResultsCtrl instance.
So whats the best way around this? I want to reuse the Results and Search View code since its basically the same. But I need to render each pair independently on the same page a few times.
I think the HTML structure you need is something like this.
<!--First-->
<div ng-controller="SearchCtrl">
<div ng-controller="ResultsCtrl">
</div>
</div>
<!--Second-->
<div ng-controller="SearchCtrl">
<div ng-controller="ResultsCtrl">
</div>
</div>
This HTML structure would help you to use independently the search results one's parent SearchCtrl created in ResultsCtrl.
jsfiddle is here.
I hope this would help you. :)
I'm trying to use ng-include with ng-init to re-use the same component by only changing its data.
The component code ("slider.html", which has no controller) looks like this:
<div ng-repeat="person in persons">
{{person.name}}
</div>
From the main view, I want to reuse the same component changing "persons" list so in the view I have:
<!--slider #1 -->
<div ng-init="persons=english" ng-include ="'inc/app/views/widgets/slider.html'"></div>
<!-- slider #2 -->
<div ng-init="persons=german" ng-include ="'inc/app/views/widgets/slider.html'"></div>
and in the controller I initialize the 2 lists "english" and "german" like this:
$scope.english = records.filter(function(t){return t.nationality=="english";});
$scope.german = records.filter(function(t){return t.nationality=="german";});
What happens is that the 2 components shows the same list of data (german); is there a way to bind the 2 different sets to the components?
That (having both lists being set as German) happens because, at the end, you are only using one controller, which has only one scope in which the persons varaiable exists. When AngularJS starts its bootstrapping process, it processes the first ng-init, updating the current controller's persons variable to English. Then it processes the second ng-init, updating again the same persons variable now to German. Then, when the ng-repeat is rendered, it will take the current and unique persons variable data, hence, being everything in German.
What you can do is to have an independent controller per component (slider.html), so each controller will have its own binding variables so you can create a persons variable for each one and initialize every controller's variable independently with your ng-init directive. Example:
<div ng-controller="MySubController" ng-repeat="person in persons">
{{person.name}}
</div>
...
<!--slider #1 -->
<div ng-init="initMySubController(english)" ng-include ="'inc/app/views/widgets/slider.html'"></div>
<!-- slider #2 -->
<div ng-init="initMySubController(german)" ng-include ="'inc/app/views/widgets/slider.html'"></div>
In a JS file:
var myApp = angular.module('myApp',[]);
myApp.controller('MySubController', ['$scope', function($scope) {
$scope.persons = [];
$scope.initMySubController = function(personsData) {
$scope.persons = personsData;
}
}]);
I am experimenting with the AngularJS approach for PhoneJS. So far I am really enjoying both frameworks.
Current issues:
Using a dx-gallery or dx-list with a datasource and a template will cause the initial un-bound template to be rendered when the view is navigated.
I found this out once I started using the dx-gallery widget and specifying a template. The console will show a network request for the initial template (not bound) being requested.
Code
<div dx-gallery="{ dataSource: imagesDataSource, height:'60%' }">
<div data-options="dxTemplate: { name: 'item' }">
<img src="http://somehostingcompany.com/{{public_id}}.jpg">
</div>
Question:
How can I not have the initial HTML template rendered when using a PhoneJS dx-gallery widget and a template?
Use ns-src binding instead of specifing src directly:
<img ng-src="http://somehostingcompany.com/{{public_id}}.jpg" />
Check out link https://docs.angularjs.org/api/ng/directive/ngSrc