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
Related
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.
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.
I'm creating my first Angular app and ran into a couple things that I just can't figure out. Whenever I include this:
<button ng-hide="results.length === projects.length" ng-click="limit = limit +3; gotoBottom()">Show More</button>
Inside of my template the app refuses to load but if I paste it anywhere outside of the template it works fine. I'd like to keep the button inside the template if at all possible so what on earth am I doing wrong?
Also, I'd like that button to also scroll to the #footer div and the ng-click doesn't seem to run this bit code:
$scope.gotoBottom = function() {
$location.hash('footer');
$anchorScroll();
};
I've created a Plunker of my code that can be found here:
https://plnkr.co/edit/MP4Pp4WLcn5EFb3pTEXx
By "template" if you are talking about projects template. Here is what you need to do.
Explanation:
The projects template need to have only one root element, so I added a div to wrap your project listing and show more button.
<div>
<div class="cards" ng-init="limit = 3">
<div class="card" ng-repeat="project in projects | limitTo: limit as results">
<div class="card-image">
<img src="{{project.img}}" alt="{{project.name}}" />
</div>
<div class="card-copy">
<h2>{{project.name}}</h2>
<p>{{project.desc}}</p>
<p><i class="fa fa-location-arrow"></i></p>
</div>
</div>
</div>
<button ng-hide="results.length === projects.length" ng-click="limit = limit +3; gotoBottom()">Show More</button>
<div id="footer" name="footer"></div>
</div>
For auto scroll: inject $timeout service
Explanation:
You did not had any div named footer so I added one just below the show more button and added a 100ms timeout, so that after your 3 projects load, it will scroll to the footer div. $timeout is very necessary because need to first render your projects and then scroll.
$scope.gotoBottom = function() {
$timeout(function() {
$location.hash('footer');
$anchorScroll();
}, 100);
};
Working Plunker: https://plnkr.co/edit/U3DDH57nh0Mqlpp2Txi4?p=preview
Hope this helps!
change the below code in projects.js
angular.module('portfolioApp')
.directive('projects', function() {
return {
templateUrl: 'projects.html',
controller: 'mainCtrl',
replace: true // remove directive tags
};
});
to
replace: false
it should do the trick. Plunker Link here
I currently have this site - http://dev.5874.co.uk/scd-data/ where I have a dropdown which displays results from WP-API which I am pulling in through AngularJS.
It currently combines the two sets of results as they're separate URL's, the results are in categories within a custom post type so if both posts are 'tagged' in the same category chosen they display twice. I need a way to combine the two sets of results but only showing one of the posts - I hope this makes sense. I'm very new to API data and AngularJS and I imagine there is a much simpler way of doing this. Any help would be much appreciated. Here is a snippet of my code to show how it's currently working.
Thanks in advance!
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<style>
.desc {display: none;}
</style>
<script type="text/javascript">
$(function(){
$('.selectOption').change(function(){
var selected = $(this).find(':selected').text();
//alert(selected);
$(".desc").hide();
$('#' + selected).show();
}).change()
});
</script>
<script>
var app = angular.module('myApp', []);
app.controller('northWestCtrl', function($scope, $http) {
var url = 'http://scd.blaze.wpengine.com/wp-json/posts?type=listings&filter[listing_area]=northwest';
$http.get(url).then(function(data) {
$scope.data = data.data;
});
});
</script>
<select class="selectOption">
<option>Search by Region</option>
<option>NorthWest</option>
<option>NorthEast</option>
<option>Midlands</option>
<option>EastAnglia</option>
<option>SouthEast</option>
<option>SouthWest</option>
<option>Scotland</option>
<option>Wales</option>
<option>NorthernIreland</option>
<option>ChannelIslands</option>
</select>
<div id="changingArea">
<body ng-app="myApp">
<div id="NorthWest" class="desc">
<div ng-controller="northWestCtrl">
<div ng-repeat="d in data">
<h2 class="entry-title title-post">{{d.title}}</h2>
<img src="{{d.acf.logo}}">
<div id="listing-contact">Contact: {{d.acf.contact}}, {{d.acf.position}}</div>
<div id="listing-address-1">
{{d.acf.address_1}}, {{d.acf.address_2}} {{d.acf.address_3}} {{d.acf.town}} {{d.acf.county}} {{d.acf.postcode}}
</div>
<div id="listing-phone">Telephone: {{d.acf.telephone}}</div>
<div id="listing-mobile">Mobile: {{d.acf.mobile}}</div>
<div id="listing-email">Email: {{d.acf.email}}</div>
<div id="listing-website">Website: {{d.acf.website}}</div>
<div id="listing-established">Established: {{d.acf.established}}</div>
<div id="listing-about">About: {{d.acf.about}}</div>
<div id="listing-mailingaddress">Mailing Address: {{d.acf.mailing_address_}}, {{d.acf.mailing_address_2}}, {{d.acf.mailing_address_3}}, {{d.acf.mailing_town}}, {{d.acf.mailing_county}}, {{d.acf.mailing_postcode}}</div>
<div id="listing-directions">Directions: {{d.acf.directions}}</div>
<div id="scd-link">View on The Shooting Club Directory</div>
</div>
</div>
</div>
</body>
</div>
Here is a working code pen - http://codepen.io/anon/pen/yePYdq
Angular is a great JavaScript front-end framework to choose, and you're off to a good start, but a lot of changes could be made. I've made some suggested changes for easier ways to do things below.
See this CodePen for all changes.
It looks like you've grasped the idea of ng-repeat, but there's definitely a lot of repeated HTML and JS in your view and controller, so let's see if we can do better.
Let's try this without jQuery to avoid direct manipulation of the DOM. And instead of many controllers, we can do this with a single controller.
<div ng-app="MyApp">
<div ng-controller="MyController">
...
</div>
</div>
<script type="text/javascript">
var app = angular.module('MyApp', []);
app.controller('MyController', ...);
</script>
For the dropdown, we'll use ng-repeat in our view and display the names of the shooting types from our model
...
<select ng-model="selectedListing">
<option
ng-repeat="listingShootingType in listingShootingTypes"
value="{{listingShootingType.name}}">
{{listingShootingType.name}}
</option>
</select>
...
<script type="text/javascript">
...
// Our selections/filters
$scope.listingShootingTypes = [
'All',
'Air Rifle/Air Pistol',
'Clay',
'ABT',
'Double Trap',
'English Skeet',
'English Sporting',
'Fitasc',
'Olympic Skeet',
'Olympic Trap',
'Simulated Game',
'Sport Trap/Compact',
'Universal Trench',
'ZZ/Helice',
'Rifle',
'Centrefire Target Rifle',
'Gallery Rifle',
'Muzzle Loading',
'Practice Shotgun',
'Smallbore Rifle'
];
...
</script>
With only one controller, we can still use ng-repeat for each listing.
<div ng-repeat="d in data">
<h2 class="entry-title title-post">{{d.title}}</h2>
<div id="listing-image"><img src="{{d.acf.logo}}"></div>
<div id="listing-contact">Contact: {{d.acf.contact}}, {{d.acf.position}}</div>
<div id="listing-address-1">
{{d.acf.address_1}}, {{d.acf.address_2}} {{d.acf.address_3}} {{d.acf.town}} {{d.acf.county}} {{d.acf.postcode}}
</div>
<div id="listing-phone">Telephone: {{d.acf.telephone}}</div>
<div id="listing-mobile">Mobile: {{d.acf.mobile}}</div>
<div id="listing-email">Email: {{d.acf.email}}</div>
<div id="listing-website">Website: {{d.acf.website}}</div>
<div id="listing-established">Established: {{d.acf.established}}</div>
<div id="listing-about">About: {{d.acf.about}}</div>
<div id="listing-mailingaddress">Mailing Address: {{d.acf.mailing_address_}}, {{d.acf.mailing_address_2}}, {{d.acf.mailing_address_3}}, {{d.acf.mailing_town}}, {{d.acf.mailing_county}}, {{d.acf.mailing_postcode}}</div>
<div id="listing-directions">Directions: {{d.acf.directions}}</div>
<div id="scd-link">View on The Shooting Club Directory</div>
</div>
Finally... How do we only display listings that match our selected shooting type from the dropdown? We could use a custom Angular filter!
...
<div ng-repeat="d in data | filter:isSelectedListing">
...
<script type="text/javascript">
...
// Let's define a custom Angular filter because the WordPress JSON is complex
$scope.isSelectedListing = function(listing) {
// Show nothing if nothing is selected
if (angular.isUndefined($scope.selectedListing) || $scope.selectedListing == '') {
return false;
}
// Show all if 'All' is selected
if ($scope.selectedListing == 'All') {
return true;
}
// If the shooting type we're looking for is present, show the listing.
// To do this, we parse the WordPress JSON object model.
if (angular.isDefined(listing.terms.listing_shooting_type)) {
for (var i = 0; i < listing.terms.listing_shooting_type.length; i++) {
if (listing.terms.listing_shooting_type[i].name == $scope.selectedListing) {
return true;
}
}
}
return false;
};
...
</script>
Hopefully this gives you an idea of how we better leverage ng-repeat + DRY :)
The entire CodePen is here.
I have polymer 1.0 app. In my routing.html file I have following configuration for routes.
page('/applications', function () {
app.route = 'Applications';
});
page('/claims', function () {
app.route = 'Claims';
});
I have applied data-routes attr in index.html file to map the corresponding section part.
For Ex:
<a data-route="Claims" href="/claims">
<iron-icon icon="report-problem"></iron-icon>
<span>Claims</span>
</a>
<section data-route="Claims">
<div class="vertical layout center">
<div>
<p>Getting Claims...</p>
<paper-progress value="10" secondary-progress="30" class="" indeterminate elavation="4"></paper-progress>
</div>
</div>
</section>
So the main problem occurs when I try to change the routes through a function. In my case I am calling a function on paper-fab tab event
I want to change the route when a user click on paper fab, to achieve this I defined a method "createApplication" in app.js
app.createApplication = function() {
app.route = 'Create Application';
};
and section part for this route in index.html file
<section data-route="Create Application">
<div class="vertical layout center fit">
<p> Some content</p>
</div>
</section>
The problem is when I click on the paper -fab its not changing the route in browser but same code runs fine in mobile.