Changing expression provided to ngShow attribute using controller - angularjs

I am using ng-show and ng-hide to display/hide content. I would like to change the showme status from true to false within the controller. But when I use the code below, it doesn't work. I'm using the Controller As syntax. Any suggestions on how to get this working right?
HTML:
<h1 ng-show="showme">Confirm Order</h1>
<h4 ng-hide="showme">Contact Information</h4>
Javascript:
.controller('ContactFormCtrl',
function ($http, serviceF, $scope) {
var contactForm = this;
$scope.$watch(serviceF.get, function(valid)
{
if (valid === 'yes') {
contactForm.showme=true;
}
else
{
contactForm.showme=false;
}
});
});
Service:
.service('serviceF', function() {
var valid = 'true';
return {
get: function () {
return valid;
},
set: function (value) {
valid = value;
}
};
UI Router:
.state('payment', {
url: '/payment',
views: {
// . . .
'top': {
templateUrl: 'views/clientinfo.html',
controller: 'ContactFormCtrl as contactForm'
// . . .
}
})

I'm not sure what you're trying to do, but the Controller As syntax goes this way in HTML:
<div ng-controller="ContactFormCtrl as contactForm">
<h1 ng-show="contactForm.showme">Confirm Order</h1>
<h1 ng-show="contactForm.showme">Confirm Order</h1>
</div>
Note the 'as contactForm' thingy passed in the ng-controller directive
Now you know that showme is actually a property of contactForm which is essentially an "alias" of the ContactFormCtrl controller
From there, whenever the showme property changes in the controller, the view will behave accordingly.
// In your controller
var contactForm = this; // aliasing this
contactForm.showme = true; //or false
UPDATE:
Since you're using ui-router, you should be good without ng-controller in your view. I'm noticing you are not passing $scope to your controller, that could be a reason why $scope.$watch isn't working, thus not updating the view.
.controller('ContactFormCtrl', function ($scope, $http, serviceF) {
var contactForm = this;
$scope.$watch(serviceF.get, function(valid) {
if (valid === 'yes') {
contactForm.showme = true;
}else{
contactForm.showme = false;
}
});
});

Related

In angular, how to call a function defined inside a controller of directive?

Here is code:
Directive code:
angular.module('app', ['localytics.directives', 'ngLoadScript'])
.directive("home", function() {
return {
restrict: "A",
replace: true,
template: "<div ng-include='var'>{{var}}</div>",
controller: function($scope) {
//loading home page - as default
$scope.var = "/tfm/home.html"
//on change the page changed dynamically!
$scope.change = function(where) {
$scope.var = where;
}
}
}
})
I WANT TO CALL chanage(where) FUNCTION OF DIRECTIVE - DEFINED IN CONTROLLER OF DIRECTIVE.
Controller Code:
.controller('wToEatController', ['$scope', function($scope) {
$scope.submitInfoAboutTable = function() {
//validation for time selection
if($scope.idealTableTime == undefined || $scope.rightTableTime == undefined) {
return;
}
//Booking details to be updated - here users preference is updating!
var bookingDetails = {
idealTableWaitTime: $scope.idealTableTime,
rightTableWaitTime: $scope.rightTableTime
}
//Let's update booking information - the booking key will be same used while login, public/tfm.html
FirebaseDbService.updateBooking(function(isUpdated) {
console.log(isUpdated);
//I WANT TO CALL chanage(where) function of DIRECTIVE
$scope.change = "change('/tfm/home.html')";
}, bookingDetails, bookingKey);
}
}]);
Is it possible?
You have to create an attribute with which the link will be done (in this example customAttr):
<span yourDirectiveName customAttr="myFunctionLink(funcInDirective)"></span>
And into your directive controller just set the new attribute like in the following snippet( '&' two way data binding ) , and create a connection with your directive method :
scope : {customAttr : '&'},
link : function(scope,element,attrs){
scope.myDirectiveFunc = function(){
console.log("my directive function was called");}
}
scope.customAttr({funcInDirective : scope.myDirectiveFunc});
}
And in your controller :
$scope.myFunctionLink = function(funcInDirective){
$scope.callableDirectiveFunc = funcInDirective;}
Now you can call your directive function with $scope.callableDirectiveFunc();

data-ng-class conditions is not working when changing url manually

I did a conditional statement on the div on data-ng-class and I want to somehow add this scope to the controller and specify when the url is /vegetarian to apply class 'egg' and i manually change url i want the class 'bacon' to be applied, but its not working, where I have i gone wrong?
html:
<div data-ng-class="{'egg': isVeggie, 'bacon': !isVeggie }">
Text here
</div>
controller:
app.controller('foodCtrl', function ($scope, $location) {
$scope.location = $location;
$scope.isVeggie = false;
$scope.isVeggie = function() {
if(isVeggie === $location.path('/vegetarian')) {
return true;
}
}
});
this is not working. When I type /vegetarian, the class egg is being applied, but when I change the url to something else like /breakfast, the class 'egg' remains. How can I make this work?
Thanks
Why the property and the function with the same name ? After all you will have only the function
$scope.isVeggie = false;
$scope.isVeggie = function() {
if(isVeggie === $location.path('/vegetarian')) {
return true;
}
}
Change your code to have only the function.
Only
$scope.isVeggie = function() {
if(isVeggie === $location.path('/vegetarian')) {
return true;
}
}
and markup
<div data-ng-class="{'egg': isVeggie(), 'bacon': !isVeggie() }">
Text here
</div>
You bind you ng-class directive to the property isVeggie and not the function isVeggie().
Change your html to:
<div data-ng-class="{'egg': isVeggie(), 'bacon': !isVeggie() }">
Text here
</div>
You can then remove the following line in your controller:
$scope.isVeggie = false;

Factory value not updated in model ...what I am doing wrong?

I am new to angular-js. I have two controllers (welcomeContoller,productController) and both handling the same model within the factory.
When the model getting updating by one controller(productController) it should reflect the update in another controller. (welcomeContoller)
But its not happening now.
HTML code :
<body ng-app="myApp">
<div ng-controller="welcomeContoller">
{{totalProductCnt}}
</div>
<div ng-controller="productController">
<div class="addRemoveCart">
<span class="pull-left glyphicon glyphicon-minus" ng-click="removeProduct()"></span>
<span class="pull-right glyphicon glyphicon-plus" ng-click="addProduct(1)"></span>
</div>
</div>
JS code
var myApp = angular.module("myApp", ['ui.bootstrap']);
myApp.factory("productCountFactory", function() {
return {
totalProducts:0
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory)
{
$scope.totalProductCnt = productCountFactory.totalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.totalProducts++;
alert(productCountFactory.totalProducts);
};
$scope.removeProduct = function() {
if(productCountFactory.totalProducts >=1)
productCountFactory.totalProducts--;
alert(productCountFactory.totalProducts);
};
});
Even after the addProduct is called the totalProductCnt is displaying as zero. I want to display the value for each increment.
Plunkr Link
Put the factory object reference on scope:
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.productCountFactory = productCountFactory;
});
Watch the property of the object.
{{productCountFactory.totalProducts}}
The DEMO on PLNKR.
By putting a reference on scope, on every digest cycle the watcher looks up the value of the property and updates the DOM if there is a change.
The totalProductCnt from your welcomeController isn't updated because it is assigned only once when the controller is created.
You can use several solutions to refresh the displayed value. Use a getter for your totalProducts in the factory :
myApp.factory("productCountFactory", function() {
var totalProducts = 0;
return {
getTotalProducts: function() {
return totalProducts;
},
addProduct: function() {
totalProducts++;
},
removeProduct: function() {
totalProducts--;
}
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.getTotalProducts = productCountFactory.getTotalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.addProduct();
};
$scope.removeProduct = function() {
if (productCountFactory.getTotalProducts() >= 1)
productCountFactory.removeProduct();
};
});
And update the view accordingly:
<div ng-controller="welcomeContoller">
{{getTotalProducts()}}
</div>
Plunkr Link

Angular Factory data isn't shared correctly

I'm trying to share some data from the controller in the current view to my navigation bar. but the data is shared wrong, or not synced correctly.
this is my factory:
myApp.factory('HeaderData', function () {
var data = {
Visible: true,
PageTitle: ''
};
return {
getVisible: function () {
return data.Visible;
},
setVisible: function (visible) {
data.Visible = visible;
console.log("HeaderData: " +visible);
},
getPageTitle: function () {
return data.PageTitle;
},
setPageTitle: function (title) {
data.PageTitle = title;
}
};
});
then in my controllers I'm doing the following:
myApp.controller('homeCtrl',function ($scope, HeaderData) {
HeaderData.setVisible(false);
console.log("HomeCtrl: " + HeaderData.getVisible());
});
in the Nav controller I read the data in like following:
myApp.controller('navCtrl', function ($scope, HeaderData) {
console.log("NavCtrl: " +HeaderData.getVisible());
$scope.showHeader = HeaderData.getVisible();
$scope.pageTitle = HeaderData.getPageTitle();
});
the following output is logged:
NavCtrl: true
HeaderData: false
HomeCtrl: false
So my NavContrl is loaded before my Data is set, and this is logical because it's like this in the HTML:
<div ng-controller="navCtrl">
<ng-include ng-show="showHeader" src="'../partials/common/header.html'"></ng-include>
</div>
<div ng-view></div>
So how can I make it work that my navCtrl updates the data correctly, and in this example hide the header when the $scope.showHeader is set to false?
Instead of assigning a primitive to $scope, assign an object to scope so that you can bind by reference. By binding by reference, you ensure that scope properties resolve to the same reference.
When you bind to a primitive (string, int, etc), it creates a copy of the original value on scope as soon as it is assigned. Now you have multiple copies of the variable on different scopes, and they all behave independently of each other.
myApp.factory('HeaderData', function() {
var data = {
Visible: true,
PageTitle: ''
};
return {
...
getData = function() {
return data;
}
};
});
And assign the model to scope:
myApp.controller('navCtrl', function($scope, HeaderData) {
$scope.data = HeaderData.getData();
});
And in your HTML:
<div ng-controller="navCtrl">
<div ng-show="data.Visible">HEADER</div>
</div>

angularjs ng-show not displaying as expected

I'm probably getting confused with mvc and angularjs and trying to set a boolean to control a scope variable to hide a div.
I have a list html page that includes this:
<tbody>{{isAuthorised}}
<tr ng-repeat="calendarEvent in items" id="event_{{calendarEvent.Id}}">
<td><strong>{{calendarEvent.EventTitle}}</strong><br/>{{calendarEvent.EventDescription}}</td>
<td>{{calendarEvent.EventDate | date:mediumDate}}</td>
<td><img src="{{calendarEvent.ThumbnailUrl}}" alt="" width="100" /></td>
<td>
<div ng-show="isAuthorised">
<i class="glyphicon glyphicon-edit"></i>
<a ng-click="delete()"><i class="glyphicon glyphicon-remove"></i></a>
</div>
</td>
</tr>
</tbody>
I'm outputting the value currently to try to figure out what is going on. So if I hit this page with setting the value the div shows my edit and delete buttons which I don't want. The value of the scope variable displays as {}.
I have this app.js code:
var ListCtrl = function ($scope, $location, CalendarEvent, SharedService) {
** lots of stuff removed as irrelevant **
$scope.isAuthorised = SharedService.get();
};
My login controller via a separate html content section that is setting the value (in the shared service)
var LoginCtrl = function ($scope, $location, $http, SharedService) {
$scope.login = function () {
$http.get("/AuthorisedUser/IsValidUser/" + $scope.item.ValidEmailAddress + "/")
.success(function (result) {
var isAuthorised = result.toLowerCase();
if (isAuthorised) {
SharedService.set(isAuthorised);
$location.path('/');
} else {
alert('you do not have the power!');
}
})
.error(function() {
alert('Email could not be Validated at this time');
});
}
};
the result is an MVC method returning a bool type. I thought maybe I needed to convert the bool to lower case because javascript would like it better, but maybe that's doing some implicit conversion to a string or something?! I'm not sure what I need to change in my list html to properly show that div only when the value is true. I'm coming from a .NET background with limited AngularJS understanding.
The value seems to being set, because if I put in a valid email address I'm seeing
true
in the html page where the scope variable is.
It seemed to work once in Chrome - but now that's not working, and just showing the stuff that should be hidden.
Sorry forgot to include the shared service:
EventsCalendarApp.factory('SharedService', function() {
var savedData = {}
function set(data) {
savedData = data;
}
function get() {
return savedData;
}
return {
set: set,
get: get
}
});
I think everything would be simplified in your controller, service, and UI if your service dealt with object references rather than a Boolean value (which is a primitive).
Your service:
EventsCalendarApp.factory('SharedService', function() {
var savedData = { isAuthorised: false }
function set(data) {
// overwrites savedData properties with data's properties,
// but preserves the reference
angular.copy(data, savedData);
}
function setAuthorised(authorised) {
savedData.isAuthorised = authorised;
}
function get() {
return savedData;
}
return {
set: set,
get: get,
setAuthorised: setAuthorised
}
});
Your Login controller:
var LoginCtrl = function ($scope, $location, $http, SharedService) {
// helper function to determine if str contains 'true'
function parseBoolean(str) {
return /^true$/i.test(str);
}
$scope.login = function () {
$http.get("/AuthorisedUser/IsValidUser/" + $scope.item.ValidEmailAddress + "/")
.success(function (result) {
var isAuthorised = parseBoolean(result);
if (isAuthorised) {
SharedService.set({ isAuthorised: isAuthorised });
// OR
SharedService.setAuthorised(isAuthorised);
$location.path('/');
} else {
alert('you do not have the power!');
}
})
.error(function() {
alert('Email could not be Validated at this time');
});
}
};
Your List Controller:
var ListCtrl = function ($scope, $location, CalendarEvent, SharedService) {
** lots of stuff removed as irrelevant **
$scope.savedData = SharedService.get();
};
HTML:
<tbody>{{savedData.isAuthorised}}
<tr ng-repeat="calendarEvent in items" id="event_{{calendarEvent.Id}}">
<td><strong>{{calendarEvent.EventTitle}}</strong><br/>{{calendarEvent.EventDescription}}</td>
<td>{{calendarEvent.EventDate | date:mediumDate}}</td>
<td><img ng-src="{{calendarEvent.ThumbnailUrl}}" alt="" width="100" /></td>
<td>
<div ng-show="savedData.isAuthorised">
<i class="glyphicon glyphicon-edit"></i>
<a ng-click="delete()"><i class="glyphicon glyphicon-remove"></i></a>
</div>
</td>
</tr>
</tbody>
When you use object references, then any changes to the reference from within your service is automatically propagated to the views; as do any changes to the reference that happen inside a controller. There is no real magic behind this - they are automatically updated because they are the same reference. In contrast, when you use primitives, then a copy of the value is passed around, and it becomes more challenging to keep them all in synch.
NOTE: on an unrelated note, you should use ng-src for image URLs that are binding expressions. This ensures that the image URL is only downloaded by the browser after the expression is evaluated and rendered.
var LoginCtrl = function ($scope, $location, $http, SharedService) {
$scope.login = function () {
$http.get("/AuthorisedUser/IsValidUser/" + $scope.item.ValidEmailAddress + "/")
.success(function (result) {
$scope.isAuthorised = result.toLowerCase();
})
.error(function() {
alert('Email could not be Validated at this time');
});
}
};
Keep one thing in mind you $scope works as a bridge between controller and view. if your controller update $scope, your view gets changed.
Don't use sharedservice here. its useless for what you want to do. try my above snippet.
So the answer was to update the ListCtrl to have this logic:
var ListCtrl = function ($scope, $location, CalendarEvent, SharedService) {
var authorised = SharedService.get();
if (authorised != "true")
$scope.isAuthorised = false;
else
$scope.isAuthorised = SharedService.get();
};
It now seems to be working! I'm still confused about the handling of booleans in javascript as I seem to have a mix of boolean and string going on in the various methods.

Resources