I have html button
<button id="postChanges" ng-show="changes.available" data-ng-click="postChanges()">Save</button>
and controller for this view
myApp.controller('myController', ['$scope', function ($scope) {
var changes = {
available : false
}
$scope.postChanges = function () {
console.log('changes before: ' + changes.available);
if (changes.available) {
changes.available = false;
}
else {
changes.available = true;
}
console.log('changes after: ' + changes.available);
}
}]);
I want to make button visible if changes.available are true and hide it when it is false but it doesn't work. I also tried with just boolean value changes = true / changes = false, data-ng-show instead of ng-show '!' before value (ng-show="!changes.available" or ng-show="!changes") but none of this solutions worked. I'm logging changes value in console and it seems it is ok so I suppose it is a problem with button attribute but I have no clue why :(
Changes.available needs to be on $scope ...
var changes = {
available : false
};
... to ...
$scope.changes = {
available : false
};
This should do it. The ng-show on the button needs to be able to see the variable.
should be
$scope.changes = {
available : false
}
Otherwise it is not visible for the ng-show directive to use.
Related
I'm trying to load a page with a pre-filled value in an input field. The page and value do load, although it doesn't trigger anything in the filtered results until I enter something on the keyboard. Is there a way around this? I'd like it to just load the filtered results once the page loads.
I'm new to Angular JS, but appreciate any sort of help or push in the right direction.
I have tried:
ng-init="search.keywords='initial'" on the input tag and that doesn't seem to cause any filtering at happen.
$scope.search = { keywords: 'initial' }; also loads the initial value, but doesn't trigger any filtering.
<input type="text" id="search-keywords" ng-model="search.keywords"
class="form-control" placeholder="Keyword search">
$scope.$watch("search", function (newVal, oldVal) {
if (newVal) {
$scope.doFilter(newVal);
}
}, true);
$scope.doFilter = function (search) {
$scope.filtering = true;
$scope.filteredCourses = $scope.filterExactMatchExceptNull($scope.courses, "inst", search.inst);
$scope.filteredCourses = $scope.filterExactMatchExceptNull($scope.filteredCourses, "fos", search.fos);
$scope.filteredCourses = $scope.filterCutoff($scope.filteredCourses, search.min, search.max);
$scope.filteredCourses = $filter("filter")($scope.filteredCourses, {
code: search.code,
name: search.name,
poa: search.poa
});
$scope.filteredCourses = $scope.filterByKeywords($scope.filteredCourses, search.keywords);
$scope.limit = 15;
if ($scope.limit >= $scope.filteredCourses.length) {
$scope.limit = $scope.filteredCourses.length;
}
$scope.filtering = false;
};
$scope.filterByKeywords = function (courses, keywords) {
if (!keywords || keywords == "") {
return courses.filter(function (course) {
return true;
});
}
var keywordArr = keywords.toLowerCase().trim().replace(/\W+/g, " ").replace(/\s\s+/g, " ").split(",");
return courses.filter(function (course) {
var matched = false;
for (var i = 0, length = keywordArr.length; i < length; i++) {
if (course.keywords && course.keywords.indexOf(keywordArr[i]) > -1) {
matched = true;
break;
}
}
return matched;
});
};
Any help would be greatly appreciated!
$watch function is used to detect any change in the inputfield after it is loaded into DOM.
So, to work it for the first time you may do:
Either use ng-init on the element to fire filter method on DOM load.
ng-init="doFilter(search)"
Or
Call filter function one time at controller level itself before actual watch starts.
$scope.search = { keywords: 'initial' };
$svope.doFilter($scope.search);
You could specify the method which should be executed on initialization of the page in the ng-init directive:
ng-init="doFilter({keywords: 'initial'})"
I have a little concern here
This comes from a service named BetSlipFactory
removeSlip: function(slip) {
return betSlipSelectionRequest('/betSlip/removeSelection', {
game: slip.game,
pair: slip.pair,
line: slip.line
});
}
Then I have this function in the controller for that service
$scope.removeSlip = function(slip) {
$rootScope.$broadcast('betSlip:removeLines', slip);
BetSlipFactory.removeSlip(slip)
}
Next I have a controller in a different scope named LinesCtrl and I have this function here which calls a couple functions from the service BetSlipFactory which is like a kind of toggle function
$rootScope.$on('betSlip:removeLines', function(event, slip) {
if (slip) {
BetSlipFactory.remove(line, row, type);
};
});
$scope.addLineToBetSlip = function(line, row, type) {
var spreadSelected = (row.spreadSelected && type === 'spread'),
totalSelected = (row.totalSelected && type === 'total'),
moneyLineSelected = (row.moneyLineSelected && type === 'moneyline');
if (spreadSelected || totalSelected || moneyLineSelected) {
BetSlipFactory.remove(line, row, type);
}else {
BetSlipFactory.add(line, row, type);
}
};
And then the HTML:
<button ng-click="removeSlip(slip)"></button>
And:
<td ng-class="!row.moneyLineSelected ? 'lines-hover' : 'line-selected'">
<a ng-click="addLineToBetSlip(line, row, 'moneyline')">
<span ng-hide="row.noMoneyLine">{{:: row.moneyLine}}</span>
</a>
</td>
What I need: combine the scopes, when the function $scope.removeSlip(slip) is call, also I need to call $scope.addLineToBetSlip(line, row, type) and then that function should call BetSlipFactory.remove(line, row, type); as it is within that if statement.
When I call $scope.removeSlip(slip) I need to kill slip parameter, within the scope of BetSlipFactory everything works great.
I recorded a video for you to see what I am talking about, let me explain the video a little bit.
In the first 2 tries you might see that I am able to select and deselect and everything works great, but in the 3rd and 4th try, you see that I select a line, and then I go a call and removeSlip(slip) when I play the X on the right, and in order to deselect the line on the left I have to do it manually.
So I started a fiddle showing this process dumbed way down compared to the plnkr you started after. Here I am using two separate controllers and a service (factory) to manage the data. This can be done without using $rootScope or $broadcast. Hopefully you can take what I have done here and integrate it into all that code you posted on plnkr. Below you can see it is quite a simple process
the jsfiddle
HTML:
<div ng-app="TestApp">
<div id="colLeft" ng-controller="LeftController">
<div ng-repeat="bet in possibleBets">
<button ng-class="!bet.moneyLineSelected ? 'lines-hover' : 'line-selected'" ng-click="addLineToBetSlip(bet)">{{bet.name}}</button>
</div>
</div>
<div id="colRight" ng-controller="RightController">
Your Bets:<br>
<div ng-repeat="bet in bets">
Active bet: {{bet.name}} - <button ng-click="removeLineFromBetSlip(bet)">×</button>
</div>
</div>
</div>
CSS:
.lines-hover {
}
.line-selected {
background:yellow;
}
#colLeft {
width:65%;
background:#f00;
float:left;
}
#colRight {
width:35%;
background:gray;
float:left;
}
and finally the JS
var app = angular.module('TestApp',[]);
app.controller('LeftController', function($scope, BetSlipFactory)
{
// this data is the data from your DB
$scope.possibleBets = [
{name:'Bet 1',moneyLineSelected:false},
{name:'Bet 2',moneyLineSelected:false},
{name:'Bet 3',moneyLineSelected:false}
];
// now that I think about it, addLineToBetSlip is not a good name
// since it actually toggles the bet
$scope.addLineToBetSlip = function(bet)
{
bet.moneyLineSelected = !bet.moneyLineSelected; // toggle the moneyLineSelected boolean
(bet.moneyLineSelected) ? BetSlipFactory.add(bet) : BetSlipFactory.remove(bet); // add or remove the bet
};
});
app.controller('RightController', function($scope, BetSlipFactory)
{
$scope.bets = BetSlipFactory.getAllBets(); // link to all the active bets
// remove the bet from the factory
$scope.removeLineFromBetSlip = function(bet)
{
bet.moneyLineSelected = false;
BetSlipFactory.remove(bet);
};
});
app.service('BetSlipFactory', function()
{
//a place to keep active bets
var theBets = [];
return {
add: function(bet)
{
// actually add the bet to this local array
theBets.push(bet);
},
remove: function(bet)
{
// you should do error checking of the index before removing it
var index = theBets.indexOf(bet);
theBets.splice(index,1);
},
getAllBets: function()
{
//simply return all active bets
return theBets;
}
}
});
function log(msg)
{
console.log(msg);
}
Important Edit
The problem doesn't occur with an ng-hide we removed that code for a bootstrap collapse, but it still occurs. My next guess is the following piece of code
<div ng-include="getTemplateUrl()"></div>
This is the whole directive:
stuffModule.directive('stuffDirective', function ($compile) {
var oldId = undefined;
return {
restrict: 'E',
scope: {
model: '='
},
link: function (scope, elem, attrs) {
scope.$watch(function (scope) {
if (oldId !== scope.model.key) {
oldId = scope.model.key;
return true;
}
return false;
}, function (newValue, oldValue) {
if (scope.model.someswitch) {
switch (scope.model.someswitch) {
case 'condition1':
scope.getTemplateUrl = function () {
return 'condition1.html';
}
break;
case 'condition2':
case 'condition3':
scope.getTemplateUrl = function () {
return 'condition23.html';
}
break;
default:
break;
}
} else {
scope.getTemplateUrl = function () {
return 'default.html';
}
}
});
},
template: '<div ng-include="getTemplateUrl()"></div>'
};
});
Just a short clarification, it is literally not possible to scroll with the mouse, but you can easily tab through the fields.
PS: It only happens in Internet Explorer 11, that is the version our customer is using. In Firefox I don't have that problem.
We replaced the code
Because there is an important presentation tomorrow and a missing scrollbar is something like a really big issue, we decided to remove the piece of code and replace it with just normal routing.
Thanks to all commentors :)
Original question with ng-hide
I have a simple page, where I hide a part with ng-hide. When ng-hide turns false the part gets shown, but randomly the page is not scrollable until I reload the whole page.
If it helps, the data which turn ng-hide to false come from an AJAX request.
EDIT 1 - not relevent anymore
Here is the code which does the HTTP requests
this.getCall = function (url) {
var dfd = $q.defer();
$rootScope.loading = true;
$rootScope.loadingError = false;
$rootScope.progressActive = true;
$rootScope.loadingClass = "progress-bar-info";
$http.get('http://localhost/something', {
cache: true
}).success(function (data) {
$rootScope.loadingClass = "progress-bar-success";
$rootScope.progressActive = false;
$timeout(function () {
$rootScope.loading = false;
}, 500);
dfd.resolve(data);
}).error(function (data, status, headers) {
$rootScope.loading = false;
$rootScope.loadingError = true;
$rootScope.progressActive = false;
$rootScope.loadingClass = "progress-bar-danger";
console.error(data);
dfd.reject(JSON.stringify(data));
});
return dfd.promise;
};
The properties on $routescope are there to show a simple progress bar for every HTTP request.
Many things are weird in your code. $scope.watch callback will be executed when the first function will return a result that is different than the last time it was executed. You will certainly not obtain the expected behavior with what you have: instead simply watch for model.key
Another problem is the way you redefine getTemplateUrl: you should not redefine a function, but change what it returns, as pinted out by #New Dev in a comment.
Fixed directive:
link: function (scope, elem, attrs) {
// Or simply bind templateUrl in your ng-include
scope.getTemplateUrl = function() {
return scope.templateUrl;
}
scope.$watch('model.key', function (newValue) {
if (scope.model.someswitch) {
switch (scope.model.someswitch) {
case 'condition1':
scope.templateUrl = 'condition1.html';
break;
case 'condition2':
case 'condition3':
scope.templateUrl = 'condition23.html';
break;
default:
break;
}
} else {
scope.templateUrl = 'default.html';
}
});
}
Now your scrolling issue has probably nothing to do with that. If the template is right but the scrolling wrong, you should investigate as to what is causing that specific issue. For us to help, we need a way to reproduce or understand the issue.
It could have to do with your ng-include being empty until your watch triggers. You can try using an ng-if, as this will only include your element in the DOM when the ng-if expression is true.
template: '<div ng-if="!whatever you had in your ng-hide" ng-include="getTemplateUrl()"></div>'
I found the solution and it didn't had anything to do with ng-include. The problem was, we use a bootstrap modal that we open like this:
$('#modal').modal('show');
But it does not hide properly, the result is that the body keeps the class modal-open that causes that the scrolling doesn't work anymore.
Thanks to everybody who helped and invested time.
I'm stumped with this one and would really appreciate someone's help.
I'm customizing highslide for integration with wordpress. Via the following code within the highslide.config.js file I'm adding a class name to certain elements and passing different attributes through an onClick call depending on certain conditions.
Everything works until I add the following code:
if(hsGroupByWpGallery){
slideshowGroup: this.parentNode.parentNode.parentNode.id
};
When the above code is present, not only does that one statement not execute, but the whole thing stops working. Even if the if statement is something like if(1=1){}; it still breaks.
If I have instead simply slideshowGroup: this.parentNode.parentNode.parentNode.id or nothing (the two options I'm looking for), both do what I would expect. I just need an if statement to switch between them.
Here's the relevant code:
jQuery(document).ready(function() {
var hsCustomGalleryGroupClass = 'fbbHighslide_GalleryGroup';
var hsCustomGalleryGroupChecker = 0;
var hsGroupByWpGallery = true;
jQuery('.' + hsCustomGalleryGroupClass).each(function(){
hsCustomGalleryGroupChecker++;
return false;
});
if (hsCustomGalleryGroupChecker > 0){
jQuery('.' + hsCustomGalleryGroupClass).each(function(i, $item) {
var grpID = $item.id;
jQuery('#' + grpID + ' .gallery-item a').addClass('highslide').each(function() {
this.onclick = function() {
return hs.expand(this, {
slideshowGroup: grpID
});
};
});
});
} else {
jQuery('.gallery-item a').addClass('highslide').each(function() {
this.onclick = function() {
return hs.expand(this, {
// This is the problem if statement
if(hsGroupByWpGallery){
slideshowGroup: this.parentNode.parentNode.parentNode.id
};
});
};
});
};
});
Thanks in advance.
The problem is you are trying to assign a conditional property.. you can't have a if condition inside a object definition like that
jQuery('.gallery-item a').addClass('highslide').each(function () {
this.onclick = function () {
var obj = {};
//assign the property only if the condition is tru
if (hsGroupByWpGallery) {
obj.slideshowGroup = this.parentNode.parentNode.parentNode.id;
}
return hs.expand(this, obj);
};
});
Another way to do the same is
jQuery('.gallery-item a').addClass('highslide').each(function () {
this.onclick = function () {
//if the flag is true sent an object with the property else an empty object
return hs.expand(this, hsGroupByWpGallery ? {
slideshowGroup: this.parentNode.parentNode.parentNode.id
} : {});
};
});
I think you might want this, based on the other code:
jQuery('.gallery-item a').addClass('highslide').each(function() {
this.onclick = function() {
if(hsGroupByWpGallery){
return hs.expand(this, {
slideshowGroup: this.parentNode.parentNode.parentNode.id
});
}
};
});
I'm trying to pass in a $scope that I want to change the value on.
These are two switch button on the same page that.
View
<div class="input">
<switch state="false" toggle="user.emailNotification">
<flip></flip>
</switch>
</div>
<div ng-click="saveNotifySettings()" class="button fill primary">Vista</div>
Controller
app.controller('notifySettingCtrl', function($scope, Users){
Users.get().$promise.then(function(data) {
$scope.user = data;
console.log($scope.user.emailNotification);
});
$scope.saveNotifySettings = function() {
console.log("PUT the new value for the switch");
};
});
When I press the button the state changes from false to true
First I want to init the state with the existing value from $scope.user.emailNotification and then change it and pass the changes to the controller.
The beginning of the my directive.
switch directive
(function() {
define(['angular', 'app', 'underscore'], function(angular, app, _) {
app.directive('switch', function() {
return {
restrict: 'E',
scope: {
value: '&toggle',
},
link: function(scope, element) {
var x = scope.value();
element.bind('mouseenter', function() {
console.log(x);
});
var $element = angular.element(element),
uniqueId = _.uniqueId('switch-'),
state = $element.attr('state');
state = typeof state === 'undefined' ? false : state;
$element.data('uniqueId',uniqueId)
.attr('state',state)
.attr('alive',true);
$element.on('click.'+uniqueId,function(){
if (state === true) {
$(this).attr('state',false);
state = false;
} else {
$(this).attr('state',true);
state = true;
}
});
}
};
});
});
}).call(this);
I'm very new at creating directives, so any help is well appreciated.
I have spend way to much time at this and it getting frustrating :/
Update:
I have created http://jsfiddle.net/HuLn4/. I have taken the pointers from you and refactored.
TLDR: I'm trying to create directive by sending in the model that I want to change in this case user.emailNotification and when the element is clicked on it changes the value from true/false and false/true and stores it back to the controllers $scope.user so it can be PUT to server and the state attribute is only to tell the look on the switch and for the initialize on the button ( on / off ).