Ok, I know the following code is wrong since it's not working. But hopefully it'll help describe what I'm trying to do:
Choose a new background color for the site:
<select name="bgcolor" onChange="ModifyColorsInLess();" id="bgcolor" ng-change="changeCurrent('bgcurrent');">
<option ng-repeat="color in colorlist" value="{{color}}" ng-selected="color==bgcurrent" >{{color}}</option>
</select>
Now, you'll see I have two things that I want to happen on a selection.
1) Hit the JS function ModifyColorsInLess() which this does and does perfectly. The function is sitting in a regular JS file. This changes the actual value of a LESS variable immediately.
2) Hit the function in the controller of changeCurrent(). This is an attempt to change the value of a scope variable set in the Angular controller.
I'm trying to figure out how to make the code do both.
EDIT:
Controller code:
app.controller('HomeController', ['$scope', '$location', '$sce', '$routeParams', '$timeout', function($scope, $location, $sce, $routeParams, $timeout ) {
// Configuration Variables:
$scope.title = "Site Title";
$scope.logosrc = "images/site_logo.gif";
$scope.tagline = "This is the new tagline!!!";
$scope.bgcurrent = "White";
$scope.pccurrent = "Black";
$scope.sccurrent = "LightGray";
$scope.dtccurrent = "Black";
$scope.ltcurrent = "LightGray";
// This changes the shadowed aspect of the top nav and footer based on a checkbox
$scope.shadowChange = function(cb){
var isChecked = (document.getElementById('shadow').checked);
if(isChecked){
$('#footer').addClass('shadowed');
$('.nav').addClass('shadowed');
$('.show-menu').addClass('shadowed');
}else{
$('#footer').removeClass('shadowed');
$('.nav').removeClass('shadowed');
$('.show-menu').removeClass('shadowed');
};
return true;
};
// This converts any HTML code in the text to actual code so that it renders properly
$scope.renderHtml = function(html_code)
{
return $sce.trustAsHtml(html_code);
};
// This sets a default value for the passed parameter. $routeParams.action in this example
if(!(typeof $routeParams.action === 'undefined')){
$scope.pageAction = $routeParams.action;
}
else{
$scope.pageAction = "home";
}
// This changes a default color
$scope.changeCurrent = function(varname){
alert(varname);
// $scope[varname] = valname;
};
}]);
Related
I've looked at a half dozen examples, but none of them seems to work for me - maybe because of the peculiar var myController = [] format of the code I inherited.
.cshtml:
<div id="ng-app" ng-app="cmorApp">
<div
data-ng-controller="myCtrl"
data-ng-init="referralId = #Model.ReferralId">
...
This works, inasmuch as my page correctly renders the value I seek:
data-ng-init="referralId = 12345"
Now I'm just trying to capture it in my controller.
Controller:
var myCtrl = ['$scope', '$http', 'FileUploader',
function ($scope, $http, FileUploader, referralId) {
console.log(referralId);
//$scope.init = function (referralId) {
// console.log(referralId);
//}
//$scope.init();
It outputs undefined.
What am I missing?
.
UPDATE:
This sort of works:
ng-init="init(#Model.ReferralId)
.
$scope.init = function (referralId) {
$scope.referralId = referralId;
}
The problem is, the value is not there when I need it. It only there if I let the page do some processing.
I can't do this, or I'm back to undefined:
$scope.init = function (referralId) {
$scope.referralId = referralId;
}
console.log($scope.referralId);
I have this html
<div ng-controller = "RetrieveCtrl as retrieve" >
<form>
<input ng-model = "retrieve.input1">
<input ng-model = "retrieve.input2">
<button type="submit" ng-click="retrieve.retrieveEntry()">Search</button>
.
.
.
with this controller
app.controller('RetrieveCtrl', ['$scope' , '$http', function($scope, $http) {
$scope.retrieveEntry = function () {
var input1 = $scope.retrieve.input1;
var input2 = $scope.retrieve.input2;
// validate input1 & input2 first...
// input1 & input2 part of URL
$http.get(...
)
};
}
which is working fine, I was able to retrieve my data from the web service. What I want to do is to refactor the function into two:
app.controller('RetrieveCtrl', ['$scope' , '$http', function($scope, $http) {
$scope.clickSearch = function() {
var input1 = $scope.retrieve.input1;
var input2 = $scope.retrieve.input2;
// validate input1 & input2 first...
$scope.retrieveEntry(input1, input2);
};
$scope.retrieveEntry = function (a, b) {
// build a and b in URL
$http.get(...
)
};
}
so that I could reuse $scope.retrieveEntry on other functionalities. However, a and b becomes undefined, after I split the function into two (button's ng-click is updated to "retrieve.clickSearch()"). I suspect it has to do with $scope, which I don't have much clear understanding of what's going on (I'm still quite confused with this and $scope) Could someone explain what's happening behind and how to resolve this?
Thanks.
I am not sure whether this would solve your issue, but you are not making correct use of controller as syntax. You controller implementation should look something like this:
app.controller('RetrieveCtrl', ['$scope' , '$http', function($scope, $http) {
var self=this;
self.clickSearch = function() {
// validate input1 & input2 first...
self.retrieveEntry(self.input1, self.input2);
};
self.retrieveEntry = function (a, b) {
// build a and b in URL
$http.get(...
)
};
}
Once you start using controller as syntax you mostly add functionality to your controller not scope directly.
I have a very simple angular app that pushes data in without refreshing the page using setInterval. Now, how can I listen or watch for new data/changes, so that if the new value/data differ from the previous one a new css style will be applied to that particular new value (for example it will change the font color to red).
My code is below:
view:
<h1>{{title}}</h1>
<ul>
<li ng-repeat="friend in friends"><strong>Name: </strong>{{friend.name}} : {{friend.username}}</li>
</ul>
data:
angular
.module ('myApp')
.factory ('Friends', ['$http', function ($http) {
return {
get: function () {
return $http.get ('users.json').then (function (response) {
return response.data;
});
}
};
}]);
Controller:
angular
.module ('myApp')
.controller ('summaryCtrl', ['$scope', 'Friends', function ($scope, Friends) {
$scope.title = "Friends";
$scope.loadData = function () {
Friends.get ().then (function (data) {
$scope.friends = data;
});
};
//initial load
$scope.loadData();
var timer = setInterval(function(){
$scope.loadData();
},5000);
}]);
many thanks
Use $interval instead of setInterval, since it triggers a digest loop it will update your data automatically
angular
.module ('myApp')
.controller ('summaryCtrl', ['$scope', 'Friends', '$interval' function ($scope, Friends, $interval) {
$scope.title = "Friends";
$scope.loadData = function () {
Friends.get ().then (function (data) {
$scope.friends = data;
});
};
//initial load
$scope.loadData();
var timer = $interval(function(){
$scope.loadData();
},5000);
}]);
My recommendation would be to manually compare each friend item and assign a changeFlag whenever the data has changed.
To start, keep a reference to the old data and whenever new data comes in, compare the two, like this:
var oldData = undefined; // Somewhere in initialization.
...
Friends.get().then(function (response) {
var newData = response;
if (oldData && JSON.stringify(oldData) != JSON.stringify(newData))
{
$scope.friends = newData;
$scope.$apply(); // Force the entire page to be redrawn. You can do style bindings to change a style.
}
oldData = response;
}
This will get you half-way to your goal. You will only be refreshing the page whenever something has changed, but there is no indication as to which friend has changed. I imagine this is what you are attempting to accomplish. You want to highlight those friends that have changed.
To do this we could simply create a comparison function that applies a flag to each object that has changed. However, this code assumes that some property on each friend remains fixed. This is normally why an id property is given to each item in a database. I'm going to assume you have an id property for each friend that never changes regardless if their name, age, email, etc. does.
var changeFlagFriendsObjects = function(oldData, newData) {
var idToOldDataMap = {};
oldData.forEach(function (friend) {
idToOldDataMap[friend.id] = friend;
});
newData.forEach(function (friend) {
var oldFriendData = idToOldDataMap[friend.id];
friend.changeFlag = JSON.stringify(oldFriendData) != JSON.stringify(friend);
});
};
// You would call changeFlagFriendsObjects in the other example above. I'm sure this would be easy to figure out how to place.
Regarding binding styles in the HTML to properties, see here.
An example would be like the following:
<!-- Apply the 'highlight' style when changeFlag is true -->
<li ng-repeat="friend in friends" ng-style="highlight={changeFlag: true}"><strong>Name: </strong>{{friend.name}} : {{friend.username}}</li>
This is a simplistic example of a problem I am having. I am clearly missing something in my understanding of Angular.
A Plunker is here: http://plnkr.co/edit/VLqA22dDTgk5PyPlCOGH?p=preview
And a copy-paste of the pertinent bits below:
<div ng-controller="myController">
<div>message: <label ng-model="message"></label></div>
<div></div><button ng-click="start()">Get Message</button></div>
</div>
var app = angular.module("app", []);
app.service('GetMessage', function() {
var message;
var start = function () {
this.message = 'Hello World';
};
return {
message: this.message,
start: start
}
});
app.controller('myController', function ($scope, GetMessage) {
$scope.message = GetMessage.message;
$scope.start = function () {
GetMessage.start();
console.warn('started..');
};
});
I would expect that the label directive would be 2-way bound to the factory's message property, so that when the start() function is called and the message is updated, that the page would be too.
To update the label in this way, do I need to broadcast an event to $rootScope, listen for it in the controller, and then update the label? It seems a very manual way of doing it.. surely there is a better way.
Thank you.
You are currently using a primitive data type, which means the following line will copy the value into a new variable:
$scope.message = GetMessage.message;
Updating one will not affect the other.
An easy solution is to use an object instead:
var message = { value: '' };
var start = function() {
message.value = 'Hello World';
};
And:
$scope.message = GetMessage.message;
Now the reference to the object would be copied into a new variable instead and both would refer to the same object.
Another issue is that you are using ngModel on a label to display the value, which will not work. ngModel is normally used on input, select and textarea elements.
You can instead use ng-bind:
<label ng-bind="message.value"></label>
Or the less verbose shortcut:
<label>{{message.value}}</label>
Demo: http://plnkr.co/edit/rUgN94DAIOfQGI8tr9kl?p=preview
If you prefer to keep using primtive values you need to handle it another way. For example by using events like you mentioned. Another solution is to register a watcher to watch for changes and update the scope variable:
app.controller('myController', function($scope, GetMessage) {
var watchExpression = function() {
return GetMessage.message;
};
var listener = function(newValue, oldValue) {
if (newValue === oldValue) return;
$scope.message = newValue;
}
$scope.$watch(watchExpression, listener);
$scope.start = function() {
GetMessage.start();
console.warn('started..');
};
});
Demo: http://plnkr.co/edit/klSl1DCUlQI3Z5ih16sq?p=preview
I have created a an ng-clickfunction which is doing the basics i need, add an active state class click here. I seem to be have an issue, removing the active class when i want to click out of the active.
<div ng-click="showTooltip(activeTooltip)" ng-class="{ active: activeTooltip == active }">Tooltip!</div>
<script>
var app = angular.module('myApp', []);
app.controller('IndexController', function($scope) {
$scope.activeTooltip = 'Adam';
$scope.active = '';
$scope.showTooltip = function(active) {
$scope.active = active;
};
});
Does anyone know the correct way of doing this?
The way you have implemented it (which doesn't make much sense btw), you need to register a listener for the click event on the window object (and because we are in Angular we should use the $window service).
Every time the window object receives the click event it should reset $scope.active to ''.
Furthermore, when calling $scope.showTooltip(), we need to stop further propagation of the click event, so it doesn't reach the window object if it is captured by the <div> first.
Your controller should be changed like this:
app.controller('IndexController', function($scope, $window) {
$scope.activeTooltip = 'Adam';
$scope.active = '';
$scope.showTooltip = function (active, evt) {
evt.stopPropagation(); // Don't let it reach $window
$scope.active = active;
};
$window.addEventListener('click', function (evt) {
$scope.$apply($scope.showTooltip.bind($scope, '', evt));
});
});
See, also, this short demo.
It turned out I didn't get the actual requiements, which is that the tooltip class should be toggled (added/removed) each time the user clicks on the div. So, there is no need for an event-listener on the window and the code should be modified like this:
app.controller('IndexController', function($scope, $window) {
$scope.activeTooltip = 'Adam';
$scope.active = '';
$scope.showTooltip = function (active) {
$scope.active = ($scope.active === active) ? '' : active;
};
});
<div ng-class="{active:activeTooltip===active}"
ng-click="showTooltip(activeTooltip)">
Tooltip!
</div>
See, also, this other short demo.