Angular.js $scope and controller again - javascript

I know there are many questions regarding the angular $scope by after a couple of hours I still can't figure out what is wrong. I'm using Angular.js with Ionic but the problem should be angular related.
In my App I need a "add to wishlist" function. In the productDetail view when someone tapps "add to wishlist" I add this product with a service and webSQL to the database. Now when the user goes to the wishlist view I get all saves products but the view doesn't update.
I have a file menu.html with an Ionic side-menu:
<ion-side-menu side="left" expose-aside-when="large" width="72">
<ion-content>
<ion-list ng-controller="LeftMenuCtrl">
<ion-item nav-clear menu-close ng-href="#/app/wish" ng-click="updateWishList()" ng-class="{'current': isActive('/app/wish')}">
<span class="icon icon-menu-wish"></span>
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
The "LeftMenuCtrl" handels the hover for the active menu item.
In my WishListView I would like to show the current added products:
File wishList.html
<ion-view hide-nav-bar="true" view-title="WISHLIST" ng-controller="WishlistCtrl">
<div class="bar bar-header bar-stable">
<div class="header-wrapper">
<!--heading-->
<div class="dash-slider-wrapper"" >
<div class="header-text-main">WHISH</div> <div class="header-text-sub">LIST</div>
</div>
</div>
</div>
<ion-content class="has-header">
<ion-item class="product-card" ng-repeat="product in products">
<div class="card">
EAN: {{product.ean}}
</div>
</ion-item>
</ion-content>
</ion-view>
And the controller:
app.controller("WishlistCtrl", function($scope, $state, productService) {
//gets called when the controller is loaded
productService.getWishlistProducts().then(function (products) {
$scope.products = products;
});
//gets called when the user clicks on the navi but does not
//update the $scope (or it updates the wrong $scope)
$scope.updateWishList = function () {
productService.getWishlistProducts().then(function (products) {
$scope.products = products;
});
};
})
Can anyone tell me whats wrong here please?
Edit:
This is the state for the menu link:
.state('app.wish', {
url: "/wish",
views: {
'menuContent': {
templateUrl: "templates/wish.html"
}
}
})
Edit2:
When I refresh the page, I see all added products. But not immediately. It's like the
$scope.updateWishList = function () ...
creates another $scope...
Edit3:
app.controller('ProductDetailCtrl', function($stateParams ,$state, $scope, productService, $ionicHistory, $ionicPopup) {
$scope.addToWishlist = function(ean) {
productService.addProductToWishlist(ean).then(function(response) {
if(response == "OK") {
var alertPopup = $ionicPopup.alert({
title: 'product added to wishlist',
template: 'You can go to your wishlist to see all your marked products'
});
}
});
};
})
Edit4:
I added a Plunker here: http://plnkr.co/edit/0woPfN
It´s not working but you can see the code there (I deleted unnecessary stuff)

Your problem is that you have 2 declaration of the WishlistCtrl.
Once in the app.js:
.state('app.wish', {
url: "/wish",
views: {
'menuContent': {
templateUrl: "wish.html",
controller: 'WishlistCtrl' //here is the first declaration
}
}
})
Second in the HTML:
<ion-view hide-nav-bar="true" view-title="WISHLIST" ng-controller="WishlistCtrl">
Remove either one and you'll be fine.

Finally, I got it working.
First in the StateProvicer I added a resolve method:
.state('app.wish', {
url: "/wish",
views: {
'menuContent': {
templateUrl: "templates/wish.html",
controller: 'WishlistCtrl',
resolve: {
products: function(productService) {
return productService.getWishlistProducts()
}
}
}
}
})
And to update the model when a new product gets added to the wishlist:
.controller("WishlistCtrl", function($scope, $state, productService, products) {
//set wishlist products on controller load
$scope.products = products;
//updated wishlist when a new product gets added
$rootScope.$on('updatedWishList', function() {
console.log('List has been updated. ');
productService.getWishlistProducts().then(function (products) {
$scope.products = products;
});
});
})
Easy... when you know how :D

Related

Pulling list item data through to a new view created by the scope data

Although there are a few of these questions rocking about, none of them seem to have a good working example and i cant seem to figure out how to apply it to my project.
What i want to do is pull the data through from the list item into another view to use as a profile page.
JS
var app = angular.module('passDataDemo', ['ngRoute']);
// Configure our routes
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
// Route for the global controller
.when('/', {
templateUrl: 'list.html'
})
// Route for profile
.when('/:item.firstname', {
templateUrl: 'listItemProfile.html'
})
// Fallback
.otherwise({
redirectTo: '/'
});
}]);
// Main controller
app.controller('mainCtrl', ['$scope', '$http', function($scope, $http) {
$http.get('items.json').success(function(data) {
$scope.items = data;
});
}]);
View 1 html
<ul ng-repeat="item in items">
<li>
<p>{{item.firstname}}</p>
<p>{{item.surname}}</p>
<button ng-click="viewTheProfileView()">View Profile</button>
View 2 html
<h1>ITEM PROFILE</h1>
<p>{{item.firstname}}</p>
<p>{{item.surname}}</p>
Here is my Plunker - https://plnkr.co/edit/gZj5gOZEcCOLNbdxwduw?p=preview
After looking at your plunker, I see that you are only using one controller for all of your views. Because of this, you would only need to set the value of $scope.item and it will show up in your listItemProfile.html. Therefore, I would change your button to pass in the current item to the controller: <button ng-click="viewTheProfileView(item)">View Profile</button>.
Then in your controller:
$scope.viewTheProfileView = function(item) {
$scope.item = item;
};
This will allow clicking the ITEM PROFILE button in index.html to display the correct information.

Angular: passing object to different view in same controller

I am working on an Ionic app where, I need to pass an item (json object) to a view and bind the items there.
I've gone through a lot of similar questions, likely:
Unable to access $scope variable within same controller
AngularJS: Pass an object into a state using ui-router
But, seems like none is working in my case.
Here is my HTML markup of index.html page (from where I'm passing item):
<div class="list card slide-in" ng-repeat="item in posts track by $index">
<h2 ng-bind="item.title" class="assertive"></h2>
//comes inside ng-repeat loop; I'm passing the whole json object as parameter to next view
<button class="button button-full" ng-click="getPostDetail(item);"> Read More </button>
</div>
Html Markup of posts.html page (where I need to access item):
<ion-view view-title="Read More ">
<ion-content class="card-background-page ">
<div class="list padding-20">
<h2 ng-bind="selectedPost.title" class="assertive"></h2>
</div>
</ion-content>
</ion-view>
My Config:
app.config(function ($stateProvider, $urlRouterProvider, localStorageServiceProvider) {
$stateProvider
.state('tabs.posts', {
url: "/posts",
params: {
obj: null // as per other suggestion, added a param here
},
views: {
'home-tab': {
templateUrl: "templates/post.html",
controller: 'main'
}
}
})
My Controller:
app.controller('main', function ($scope, $http, $state, $ionicModal, $location, $stateParams, localStorageService) {
$scope.getPostDetail = function (data) {
var selectedPost = data;
$state.go("tabs.posts", { obj: selectedPost });
}
})
On click of button, the Posts View loads successfully, but no content is bound i.e. the view is blank
Unless I'm missing something, selectedPost needs to be on $scope. Otherwise it cannot be accessed from the view. So something like this.
$scope.getPostDetail = function (data) {
$scope.selectedPost = data;
$state.go("tabs.posts", { obj: selectedPost });
}

Params with $state.go and $scope

I tried many things to pass data to my view, but i don't know what is wrong.
I tried with $scope and pass data with $state.go, but nothing happens.
.state('app.ler',
{
views: {
'menuContent': {
templateUrl: 'mensagens/mensagemRead.html',
controller: 'MensagensCtrl',
params: {'assunto': null}
}
},
url: '/ler'
})
$scope.read = function (id) {
MensagensService.ler(id).then(function (response) {
// $scope.mensagem_ler = response.data[0];
// alert(response.data[0].assunto);
$state.go('app.ler', {assunto:response.data[0].assunto});
console.log($stateParams);
});
};
<ion-view title="Mensagens2">
<ion-content class="has-header">
<div class="list">
<a class="item item-avatar" href="#">
<img src="venkman.jpg">
<h2>Gustavoaaa</h2>
<!--<p>{{mensagem_ler.assunto}}</p>-->
<p>{{assunto}}</p>
</a>
</div>
</ion-content>
</ion-view>
You can add the state parameter using a : in the url of your state.
.state('app.ler',
{
views: {
'menuContent': {
templateUrl: 'mensagens/mensagemRead.html',
controller: 'MensagensCtrl'
}
},
url: '/ler/:assunto'
});
This will make the property assunto available in $stateParams
params option of state is available in root level of state definition, you could not have them in leaf level of namedView.
.state('app.ler', {
views: {
'menuContent': {
templateUrl: 'mensagens/mensagemRead.html',
controller: 'MensagensCtrl',
}
},
url: '/ler/{assunto}', //here is parameter mentioned in URL
params: {
'assunto': null //parameter default value
}
})
You can get this values in $stateParams object inside your controller.
Try this in your state configurations
url: '/ler?assunto'
If you want to pass more parameters then just add them like this
url: '/ler?assunto&param2&param3....'
To use the state param in your view you can save it in a $scope variable in your controller and then use it.
For example: $scope.assunto = $stateParams.assunto;
<ion-view title="Mensagens2">
<ion-content class="has-header">
<div class="list">
<a class="item item-avatar" href="#">
<img src="venkman.jpg">
<h2>Gustavoaaa</h2>
<!--<p>{{mensagem_ler.assunto}}</p>-->
<p>{{assunto}}</p>
</a>
</div>
</ion-content>
</ion-view>

Angular reload parent controller on child state change

I am a newbie to angular JS and IONIC.
I have left side menu:
- Menu 1
- Menu 2
- Menu 3
And right side menu dynamically change based on the selected left menu.
I successfully did this. But, the problem is when i change to other Menu, my right side menu won't be updated before i refresh the page (using F5).
Whats wrong with my code:
controller.js
angular.module('starter.controllers', [])
.controller('AppCtrl', function ($state, $scope, $stateParams) {
var source = $stateParams.source;
$scope.title = source;
$scope.data = {items: []};
if (source == 'Menu1') {
$scope.data.items.push({url: source + '/AAA', label: "AAA"});
$scope.data.items.push({url: source + '/BBB', label: "BBB"});
$scope.data.items.push({url: source + '/CCC', label: "CCC"});
}
if (source == 'Menu2') {
$scope.data.items.push({url: source + '/EEE', label: "EEE"});
}
if (source == 'Menu3') {
$scope.data.items.push({url: source + '/FFF', label: "FFF"});
}
})
.controller('NewsListCtrl', function ($scope, $stateParams) {
})
;
app.js
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('app', {
url: "/app/:source/:channel",
templateUrl: "templates/layout.html",
controller: 'AppCtrl'
})
.state('app.newsList', {
url: "/news-list",
views: {
'menuContent': {
templateUrl: "templates/news-list.html",
controller: 'NewsListCtrl'
}
}
})
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/app/Menu1/AAA/news-list');
});
layout.html
<ion-side-menus enable-menu-with-back-views="false">>
<ion-side-menu-content>
...
</ion-side-menu-content>
<ion-side-menu side="left">
<ion-content>
<ion-list>
<ion-item menu-close href="#/app/Menu1/AAA/news-list">
AAA
</ion-item>
<ion-item menu-close href="#/app/Menu2/EEE/news-list">
EEE
</ion-item>
<ion-item menu-close href="#/app/Menu3/FFF/news-list">
FFF
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
<ion-side-menu side="right">
<ion-content>
<ion-list>
<ion-item menu-close ng-repeat="item in data.items" href="#/app/{{item.url}}/news-list">
{{item.label}}
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>
Since the parent controller doesn't get re-created when the child state changes, you could have the parent controller listen for $stateChangeSuccess and update the menu based on the state params:
$rootScope.$on('$stateChangeSuccess',
function(event, toState, toParams, fromState, fromParams){ ... })
https://github.com/angular-ui/ui-router/wiki#state-change-events

Ionic framework ionicView.entered event fired twice

I'm playing with this ionicView events that are fired whenever the views become active, and I'm using the side menu template that you can re-use when creating the project. It seems that if I put a listener for the $ionicView.entered event in the AppCtrl (the one used by the side menu template, which belongs to an abstract state in the ui-router configuration) it gets called twice in a row for any of the subviews (like, when using app.someotherview as a state).
I don't know if this is the expected behavior because from the documentation I would expect it to only fire once, no matter if I change the subview (the menuContent view).
I'd like to know if this is expected behavior and if so, how do I get to have an event fired only once every time it gets to show the side menu template.
This is what I've got written:
This is from the application module:
.config(function($stateProvider, $urlRouterProvider, $httpProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "templates/menu.html",
controller: 'AppCtrl'
})
.state('app.overview', {
url: "/overview",
views: {
'menuContent': {
templateUrl: "templates/overview.html",
controller: 'OverviewCtrl'
}
}
})
.state('login', {
url: "/login",
templateUrl: "templates/identificationscreen.html",
controller: "IdentificationCtrl"
})
.state('app.agenda', {
url: "/agenda",
views: {
'menuContent': {
templateUrl: "templates/agenda.html",
controller: 'AgendaCtrl'
}
}
});
$httpProvider.interceptors.push('credentialsInjector');
// if none of the above states are matched, use this as the fallback
$urlRouterProvider.otherwise('/login');
Then the AppCtrl is this:
angular.module('dashboard.controllers.app', [])
.controller('AppCtrl', function($scope, $ionicModal, $timeout, $ionicSideMenuDelegate, authService, $state) {
$scope.logout = function() {
authService.logout();
$state.go('login');
};
$scope.$on('$ionicView.enter', function(){ //This is fired twice in a row
console.log("App view (menu) entered.");
console.log(arguments);
});
$scope.$on('$ionicView.leave', function(){ //This just one when leaving, which happens when I logout
console.log("App view (menu) leaved.");
console.log(arguments);
});
});
The menu template:
<ion-side-menus enable-menu-with-back-views="false">
<ion-side-menu-content edge-drag-threshold="true">
<ion-nav-bar class="bar-stable">
<ion-nav-back-button>
</ion-nav-back-button>
<ion-nav-buttons side="left">
<button class="button button-icon button-clear ion-navicon" menu-toggle="left">
</button>
</ion-nav-buttons>
</ion-nav-bar>
<ion-nav-view name="menuContent"></ion-nav-view>
</ion-side-menu-content>
<ion-side-menu side="left">
<ion-header-bar class="bar-stable">
<h1 class="title">APPoint!</h1>
</ion-header-bar>
<ion-content>
<ion-list>
<ion-item nav-clear menu-close href="#/app/overview">
Overview
</ion-item>
<ion-item nav-clear menu-close href="#/app/agenda">
Agenda
</ion-item>
<ion-item nav-clear menu-close ng-click="logout()">
Logout
</ion-item>
</ion-list>
</ion-content>
</ion-side-menu>
</ion-side-menus>
A simple workaround is:
$scope.$on('$ionicView.enter', function(ev) {
if(ev.targetScope !== $scope)
return;
// Your code which should only run once
});
The best option that I found to simulate onEnter event was to use in view controller :
$scope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
if (toState.name == "stateName")
doSomething();
}
You can globally disable the caching mechanism used by ionic by doing:
$ionicConfigProvider.views.maxCache(0);
I haven't tried that on my own though.
Else, the best way that worked for me was doing
$scope.$on("$ionicView.afterLeave", function () {
$ionicHistory.clearCache();
});
This is to clear the cache before leaving the view to re-run controller every time you enter back again.
Try $ionicView.afterEnter. That fires only once for me.
URL
At first I used Florian's answer but noticed that in my case it's just a symptom of a root problem, because this doesn't happen to all controllers, just this one.
In my case, it happens because I was trying to incrementally migrate from Ionic/AngularJS v1 to Ionic/AngularJS v2.
I have added controllerAs in my template:
<ion-view view-title="Avatar » Instruments" ng-controller="AvatarInstrumentsCtrl as vm">
but I forgot to remove the controller reference in my app.js :
.state('app.avatar-instruments', {
url: "/avatar/instruments",
views: {
'menuContent': {
templateUrl: "templates/avatar/instruments.html",
controller: 'AvatarInstrumentsCtrl'
}
}
})
So in my case the solution is:
.state('app.avatar-instruments', {
url: "/avatar/instruments",
views: {
'menuContent': {
templateUrl: "templates/avatar/instruments.html"
}
}
})

Categories