AngularJS ui-sref not working on Andriod phone - javascript

I am experiencing a problem when trying to test my portfolio website on my mother’s mobile (Samsung Galaxy JS 3). The images and titles of the projects get loaded onto the index page from JSON with ng-repeat and the links to the information are made from the project IDs with ui-sref. The website loads on the mobile all right and it can direct to the about page, which also uses ui-sref, but it cannot direct to the child pages – it either stays on the main page, or if I force it to go to one of the pages, it displays a blank page with a toggle menu (ng-include header).
It works fine on a Sony Xperia M4, Samsung Galaxy Young, Galaxy A5, my desktop computer (Windows 8.1) and a Mac (not sure about the operating system). I’ve followed the “Hello Solarsystem” tutorial, which also seems to have the same issue when I tried the Plunker version of it on her phone this morning (7th of June).
I have ensured that the site was using the most up to date version after reading ui-sref not working in nested views, I’ve tried adding ui-view to the template that displays the project’s links as is advised on here: Ui-sref not generating clickable links/not working and I am now feeling stuck.
Sorry if my question is a bit long, but I've never had to write one before and I don't want to miss anything.
EDIT: I have now made a plunk with the exact code I'm using for the projects - Plunker and I have now removed ui-router, so it does not load the inner page as a sub page, but at least is viewable in all browsers - the plunk is using ui-router.
The code that I'm thinking has issues is being listed below.
projects.html - view
<div class="container">
<div class="wrapper">
<div class="col-xs-12 col-sm-6 col-md-4 project-block" ng-repeat="project in $ctrl.projects">
<a ui-sref="project({ projectId: project.id })" ui-sref-active="active">
<div class="grid-item university">
<div class="grid-caption">
<img ng-src="{{project.thumb}}" alt="{{project.name}} ({{project.desc}})" id="portfolio-thumb-{{project.id}}" />
<div class="titles">
<div class="grid-projects title">{{project.name}}</div>
<div class="grid-projects desc">{{project.desc}}</div>
</div>
</div>
</div>
</a>
</div>
</div>
</div>
<ui-view></ui-view>
index.html
<body ng-app="myPortfolio">
<div id="wrapper">
<header ng-include="'header.html'"></header>
<div id="page-content-wrapper">
Toggle Menu
<ui-view></ui-view>
<uir-state-vis class="statevis" width="300" height="100"></uir-state-vis>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
</div>
</body>
app.js
var myApp = angular.module('myPortfolio', ['ui.router', 'slick', 'ngAnimate', 'ngRoute', 'ngResource', 'ngTouch', 'ngSanitize', 'ui.bootstrap']);
myApp.config(function ($stateProvider) {
// An array of state definitions
var states = [
{
name: 'about',
url: '/about',
component: 'about'
},
{
name: 'projects',
url: '/projects',
component: 'projects',
// It delegates to the ProjectService to HTTP fetch (async)
// The project component receives this via its `bindings: `
resolve: {
projects: function (ProjectService) {
return ProjectService.getAllProjects();
}
}
},
{
name: 'project',
// This state takes a URL parameter called projectId
url: '/project/{projectId}',
component: 'project',
// This state defines a 'project' resolve
// It delegates to the ProjectService, passing the projectId parameter
resolve: {
project: function (ProjectService, $transition$) {
return ProjectService.getProject($transition$.params().projectId);
}
}
}
]
// Loop over the state definitions and register them
states.forEach(function (state) {
$stateProvider.state(state);
});
});
myApp.config(function ($urlRouterProvider) {
// when there is an empty route, redirect to /index
$urlRouterProvider.when('', '/projects');
});
// preload the async data
myApp.run(function ($http) {
$http.get('data/projects.json', { cache: true });
$http.get('data/info.json', { cache: true });
});
//Make html in JSON file trusted
myApp.filter('to_trusted', ['$sce', function ($sce) {
return function (text) {
return $sce.trustAsHtml(text);
};
}]);
projects.js - component
angular.module('myPortfolio').service('ProjectService', function($http) {
var service = {
getAllProjects: function() {
return $http.get('data/projects.json', { cache: true }).then(function(resp) {
return resp.data;
});
},
getProject: function(id) {
function projectMatchesParam(project) {
return project.id === id;
}
return service.getAllProjects().then(function (projects) {
return projects.find(projectMatchesParam)
});
}
}
return service;
})
projects.js - service
angular.module('myPortfolio').service('ProjectService', function($http) {
var service = {
getAllProjects: function() {
return $http.get('data/projects.json', { cache: true }).then(function(resp) {
return resp.data;
});
},
getProject: function(id) {
function projectMatchesParam(project) {
return project.id === id;
}
return service.getAllProjects().then(function (projects) {
return projects.find(projectMatchesParam)
});
}
}
return service;
})

Related

How do I establish communication between independent components in AngularJS

I have a Nav in which there are two pages representing two AngularJS components - Home and About. I want to pass user name from Home component to About component.
<div ng-app="myApp">
<ul>
<li>Home
</li>
<li>About
</li>
</ul>
<div ng-view></div>
</div>
I tried to establish the component communication using bindings with < but no luck. Basically, they are both independent components. How do I pass data from one component to another in this scenario.
I've created a working example using CodePen. Could anyone please guide how to do it.
Components and Route Config
app.component("home", {
template: `<h1>Home</h1>
Hi {{$ctrl.user}}!`,
controller: function HomeController() {
this.user = "John.";
}
});
app.component("about", {
template: `<h1>About</h1>`,
controller: function AboutController() {}
});
app.config(function($routeProvider) {
$routeProvider
.when("/home", {
template: "<home></home>"
})
.when("/about", {
template: "<about></about>"
})
.otherwise({
redirectTo: "/home"
});
});
View data is destroyed when views change. Store data that needs to persist between views in a service:
app.service("appData", function() {
var user;
this.setUser= val => user = val;
this.getUser= _ => user;
});
Use that service in the component controllers:
app.component("home", {
template: `<h1>Home</h1>
Hi {{$ctrl.user}}!`,
controller: function HomeController(appData) {
this.user = "John.";
appData.setUser(this.user);
}
});
app.component("about", {
template: `<h1>About</h1>`,
controller: function AboutController(appData) {
this.user = appData.getUser();
}
});
For more information, see
AngularJS Developer Guide - Creating services
#georgeawg already answered the question sufficiently. But I feel one should use sessionStorage when storing username or other userDetails because the date in the service gets erased when the user redirects to other pages. Hence storing it once in the sessionStorage can be very helpful.
// Create item:
var myObj = { username: 'admin', privilages: 'RAED' };
$window.sessionStorage.setItem(key, JSON.stringify(myObj));
// Read item:
var item = JSON.parse($window.sessionStorage.getItem(key));

View not injected or WARNING: Tried to load angular more than once

I'am using the version v1.0.0-rc.1 of ui-router and angular 1.6.4 with components.
The is the reduced version of the application routes. Each view is associated with a component. topbar, sidebar and pageContent are all components.
The way the code is below the main view is not injected with the pageContent component and there are no errors or warnings. But topbar and sidebar are injected.
Plunker link to reproduce it: https://plnkr.co/edit/NedgoYEjkAxaRXRJHSoL?p=preview
// Application routes
$stateProvider
.state('root', {
url: '',
abstract: true,
views: {
topbar: 'topbar',
sidebar: 'sidebar'
}
})
//children of the 'root' route
.state('income', {
url: '/income',
parent: 'root',
views: {
main: 'pageContent'
},
resolve: {
selectedModule: function () {
return 'income';
}
}
})
.state('outcome', {
url: '/outcome',
parent: 'root',
views: {
main: 'pageContent'
},
resolve: {
selectedModule: function () {
return 'outcome';
}
}
});
And this is the index.html
<ui-view name="topbar"></ui-view>
<div id="wrapper">
<ui-view name="sidebar"></ui-view>
<ui-view name="main"></ui-view>
</div>
pageContent.js
(function () {
'use strict';
angular.module('up').component('pageContent', {
templateUrl: 'app/shared-components/page-content/page-content.component.html',
controller: Controller,
bindings: {
selectedModule: '<'
}
});
function Controller() {}
})();
pageContent.html (includes other components)
<div id="page-content-wrapper">
<div class="container-fluid">
<div class="row">
<div class="col-md-12 no-padding">
<sidemenu></sidemenu>
<operations></operations>
<reports></reports>
</div>
</div>
</div>
</div>
Finally if I change the 'root' route to: (with the main view and and empty template url)
.state('root', {
url: '',
abstract: true,
views: {
topbar: 'topbar',
sidebar: 'sidebar',
main: {
templateUrl: ''
}
}
})
then I get WARNING: Tried to load angular more than once, but Everything works, meaning that all views are injected.
Another thing is that if remove jQuery the warning above is not shown. However, I need jQuery to use it with angular.element
Sorry for the long post but I had to give all the details.
Normally <script> tags aren't parsed in templates, this is a simplification in jqLite implementation that exists by design. As explained in this answer, having jQuery loaded before Angular replaces jqLite with jQuery and enables adding <script> nodes dynamically.
The problem seen in the plunk is caused by templateUrl: '' in this piece of code:
.state('root', {
url: '',
abstract: true,
views: {
topbar: 'topbar',
sidebar: 'sidebar',
main: {
templateUrl: ''
}
}
})
This results in loading index page as a template, adding duplicate <script> tags to DOM and evaluating them. If there's no component for main view, it shouldn't be in views.
Regarding the expected behaviour, the view doesn't follow naming scheme, it likely should be:
.state('income', {
url: '/income',
parent: 'root',
views: {
'main#': 'pageContent'
},
...

Angular $httpProvider interceptors stopped working for 'ng-include' after adding "UI Grid" to the app

I am trying to add Angular UI Grid to my application, following introduction tutorial Tutorial: 101 Intro to UI-Grid and faced following issue.
First, the grid works, I can create it in controller and bind to view, but
as soon as I add it to the project (just add as a module, without actually using it anywhere) interceptor that worked previously is not fired anymore, more specifically it is needed for view template loading with ng-include (see some code excerpts below).
EDIT : Please note that ng-include works, it just does not go through the interceptor, but works as there is none.
Angular 1.4.8
UI Grid 3.2.1
jQuery 2.2.0
What I tried :
Using other Angular versions,
Tried init interceptor with factory,
Changed order of modules in init array,
Tried other jQuery version.
Has anyone faced such an issue, perhaps with other modules?
HTML :
<body>
<div ng-app="app">
<div ng-controller="app.views.layout as vm">
<div ng-include="'/App/Main/views/layout/header.cshtml'"></div>
<div class="container">
<div class="angular-animation-container row">
<div ui-view class="shuffle-animation col-xs-12"></div>
</div>
</div>
</div>
</div>
</body>
Angular application initialization :
var app = angular.module('app', [
'ngAnimate',
'ngSanitize',
'ui.router',
'ui.bootstrap',
'ui.jq',
'ngTouch'
'ui.grid'
'abp',
]);
Interceptor registration :
var abpModule = angular.module('abp', []);
abpModule.config([
'$httpProvider', function ($httpProvider) {
$httpProvider.interceptors.push(['$q', function ($q) {
return {
'request': function (config) {
if (endsWith(config.url, '.cshtml')) {
config.url = abp.appPath + 'AbpAppView/Load?viewUrl=' + config.url + '&_t=' + abp.pageLoadTime.getTime();
}
return config;
},
'response': function (response) {
if (!response.config || !response.config.abp || !response.data) {
return response;
}
var defer = $q.defer();
abp.ng.http.handleResponse(response, defer);
return defer.promise;
},
'responseError': function (ngError) {
var error = {
message: ngError.data || abp.ng.http.defaultError.message,
details: ngError.statusText || abp.ng.http.defaultError.details,
responseError: true
}
abp.ng.http.showError(error);
abp.ng.http.logError(error);
return $q.reject(ngError);
}
};
}]);
}
]);
I set it up from scratch and it works now. Looks like I missed some minor configuration typo somewhere. Also apparently ui-grid doesn't interfere with angular http interception, so conclusion is that it was false alert.

Load external scripts after Angular view loaded

I load the angular views by ui-router
...
.state('app.page.search', {
url: '/search',
templateUrl: 'tpl/page_search.html'
})
I ran into XXX is not a function randomly,
How could I make sure the external files are loaded after Angular views are ready?
tpl/root_layout.html
<div data-ng-include="'tpl/header.html'"></div>
<div class="content-container no-padding">
<div class="container-full">
<!-- <div data-ng-include="'tpl/search.html'"></div> -->
<div class="app-content-body fade-in-up" ui-view></div>
</div>
</div>
<div data-ng-include="'tpl/footer.html'"></div>
tpl/page_search.html
<DOM>
....
<DOM>
<script type='text/javascript' src='js/scriptA.js'></script>
<script type='text/javascript' src='js/scriptB.js'></script>
as #Daniel Higueras suggested, use the UI Router's resolve to wait for your assets to load in
.state('state', {
url: '/state',
templateUrl: 'url/state.html',
resolve: {
asset1: function($http) {
return $http.get();
},
asset2: function($http) {
return $http.get();
}
}
}
if you want to load your assets after everything's done, you can use the ocLazyLoad service: https://oclazyload.readme.io/docs/oclazyload-service
Just use it in your controller:
app.controller('ctrl', function($ocLazyLoad) {
$ocLazyLoad.load('asset1.js').then(
function(res) {
// asset 1 is available
}
);
$ocLazyLoad.load('asset2.js').then(
function(res) {
// asset 2 is available
}
);
});
this is helpful when you have large a large asset like D3 where only one page of your app uses it, so you don't want to pull it in every time your app loads.

AngularJs Ui-view can't show correctly

I want to use ui-view and ui-router in a part of my page.But for some reason I can't get to show up my template "app_usermng_table.html".
The main code of this part is as follows:
1.router config part
(I have add the "ui.router" dependency in my module "app" yet.)
.state('app.usermng', {
url: '/usermng',
templateUrl: 'tpl/app_usermng.html',
resolve: {
deps: ['uiLoad',
function( uiLoad ){
return uiLoad.load( ['js/controllers/usermng/usermng.js','css/usermng.css'] );
}]
},
onEnter: function(){
console.log("enter usermng");
}
})
.state('app.usermng.table',{
url:'/table',
templateUrl:'tpl/app_usermng_table.html',
resolve:{
deps:[
'uiload',
function(uiload){
return uiload.load(['js/controllers/usermng/usermngtable.js'])
}
]
},
onEnter: function(){
console.log("enter usermng table");
}
})
2.app_usermng.html:
I want to put the template in the
<div ui-view></div>
tag.
<div class="hbox hbox-auto-xs hbox-auto-sm" ng-controller="UsermngCtrl">
<div ng-controller="UsermngCtrl">
<div class="bg-light lter b-b wrapper-md">
<h1 class="m-n font-thin h3">User Management</h1>
</div>
<div ui-view></div>
</div>
</div>
3.usermng controller
I add the code
$state.transitionTo
hoping when I enter the state "app.usermng", the state "app.usermng.table" can be shown in its parent.
app.controller('UsermngCtrl',['$scope','$state',function($scope,$state){
$state.transitionTo('app.usermng.table');
console.log("table")
}]);
4.navigation bar
I hope it jumps to the state "app.usermng" when I click 'UserManagement' on the navigation bar.
<li ui-sref-active="active">
<a ui-sref="app.usermng">
<i class="glyphicon glyphicon-list-alt icon text-info-dker"></i>
<span class="font-bold" translate="aside.nav.usermng">User Management</span>
</a>
</li>
However,all I've done seems to be useless...The table part isn't shown.The console content is as follows:
enter usermng
usermng.js:3 table
usermng.js:3 table
It seems that my child state "app.usermng.table" never enters.
Could anyone tell me what's the problem.Thanks a lot! :)
You need to add an 'abstract':true property, like here:
.state('app.usermng', {
url: '/usermng',
templateUrl: 'tpl/app_usermng.html',
abstract: true,
resolve: {
deps: ['uiLoad',
function( uiLoad ){
return uiLoad.load( ['js/controllers/usermng/usermng.js','css/usermng.css'] );
}]
},
onEnter: function(){
console.log("enter usermng");
}
})
.state('app.usermng.table',{
url:'/table',
templateUrl:'tpl/app_usermng_table.html',
resolve:{
deps:[
'uiload',
function(uiload){
return uiload.load(['js/controllers/usermng/usermngtable.js'])
}
]
},
onEnter: function(){
console.log("enter usermng table");
}
})
It's hard to tell what you are going for here. You are giving the table state a URL which makes me think you are wanting this to be a standalone state, in which case you need to just transitionTo that state directly instead of transitioning to the parent state. If the table state is just meant to be a piece of the parent state, there is a way to do that.
You need to use named views. If I am correct that app.usermng.table isn't a state in it's own right, it's a state that only exists to be shown as part of the app.usermng state. Therefore, when you define app.usermng, you need to declare the table as a named view.
$stateProvider
.state('app.usermng', {
views: {
'table': {
templateUrl:'tpl/app_usermng_table.html',
resolve: []
}
}
})
Then, in the parent template, in the div where you want to insert the table, you should declare it like <div ui-view="table"></div>
See here: https://github.com/angular-ui/ui-router/wiki/Multiple-Named-Views

Categories