Is there a way in which ng-init will get updated when tableCells will change ? I want to use this approach (or similar) so angular won't have to call findCellsByDate two times.
I also tried to change ng-init with ng-bind or ng-model, but bind will show [object Object] and model will throw an error as there isn't an attribution.
<span ng-init='cells = findCellsByDate(tableCells, day)'>
<div class='text' ng-show='forecastAndActualForCellsAreNotEmpty(cells)'>
<span ng-bind='getTotalHoursPercentageForCells(cells)'></span>
<span>%</span>
</div>
</span>
I don't think ng-init works that way, so what I'm thinking is that you should change some of your controller/model code to hold a boolean for forecastAndActualForCellsAreNotEmpty which would get updated.
On the other hand you could do it by css. I assume that if forecastAndActualForCellsAreNotEmpty returns false, getTotalHoursPercentageForCells would return 0. So you could bind that to a data attribute and using a css rule make the div go away. But in order to not use ng-init you would have to take the content also with css. And the only way to do that, that I know of, is with :before and :after.
Something like
<div class='text' data-percentage='{{getTotalHoursPercentageForCells(findCellsByDate(tableCells, day))}}'>
</div>
And the css
div[data-percentage=0]{
display: none;
}
div[data-percentage]:before{
content: attr(data-percentage) "%";
display: block;
}
Now I wouldn't use :before or :after to display actual application content, but rather things that are related to style. So I suppose the final recommendation would be to alter the model instead.
You can put the logic that changes the cells variable inside a watch function that observe changes in tableCells variable
$scope.$watch('tableCells', function(tableCells) {
if(!tableCells) return;
$scope.cells = findCellsByDate(tableCells, $scope.day);
});
In this way you keep that logic in the controller
Related
I'm trying to change the attribute of an object with removeAttribute to take away the hidden status of it but so far nothing seems to work.
My code seems to have no effect. Am I doing something wrong?
function changePage() {
document.getElementById.("p2");
p2.removeAtribute.("hidden") ;
}
I've also tried it all on one line as well like so
function changePage() {
document.getElementById.("p2").p2.removeAtribute.("hidden") ;
}
I've never seen the use of dots before opening parentheses.
E.g.
document.getElementById.("p2").p2.removeAtribute.("hidden") should be document.getElementById("p2").removeAtribute("hidden")
(You are also referencing the element by id after you just retrieved it, which is unnecessary.)
Your first example didn't work because you retrieved the element and did nothing with it, then tried to access a p2 variable that wasn't declared. Again, you also have the . before parentheses.
Here's the js example:
function changeVisibility()
{
var p2 = document.getElementById('p2');
switch (p2.style.visibility)
{
case 'hidden':
document.getElementById('p2').style.visibility = 'visible';
break;
case 'visible':
document.getElementById('p2').style.visibility = 'hidden';
break;
}
}
<div id="p2" style="visibility:hidden">
test
</div>
<br />
<button onclick="changeVisibility()">
change visibility with basic js
</button>
And here's the jQuery example:
function changePage()
{
$('#p2').toggle();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="p2" style="display:none">
test
</div>
<br />
<button onclick="changePage()">
change visibility with basic js
</button>
The basic JS version uses the visibility style, and you can see that it doesn't collapse the element, it only makes it invisible.
jQuery has a nice built-in .toggle function that changes the display of the element. If it is hidden, it collapses the element. When the element is displayed, it is re-assigned whatever the display style is for that element. Building that in basic js would take a lot more work, as you are then tracking state (if you want to make the method reusable). You can make jQuery work similarly to the basic js version if you use the css properties, but toggle is quite nice and simple.
Your main issue is that you were mixing the getting of the element with methods that are only available on jQuery objects. I suggest reading the jQuery tutorials for basic accessors, which can get elements by id, class name, etc.
I'm trying to have a checkbox, so when you click on the default FontAwesome empty box (fa-square-o) it gets changed with this icon (fa-check-square-o).
How can I do that with AngularJS? I need to put a function in the controller and call it from ng-click? What would be the correct function?
I found what I need in Jquery but would love to just use angular for it:
$("#checkBoxOn").click(function(event) {
$(this).find('i').toggleClass('fa-check-square-o');
If possible help me convert this in Angular!
Two parts:
You need something that holds a boolean if something is checked. We can do that using an expression like this: ng-click="toggle = !toggle". Basically, each time you click the element with that directive, toggle will become what it wasn't before.
You can use a ternary operator to set the class: i ng-class="toggle ? 'fa-check-square-o' : 'square-o'"></i>
Together, this might become something like:
<span ng-click="toggle = !toggle">
<i ng-class="toggle ? 'fa-check-square-o' : 'square-o'"></i>
Some text with the toggle here, that is also clickable.
</span>
Based on your other question, to hide another element based on this, you can add ngHide to it:
<table ng-hide="toggle">
This question is similar to AngularJS toggle class using ng-class, but that does not answer the toggling portion.
Just to make it more interesting, you could do something with unicode instead if you don't want the extra dependencies. This uses ngShow and ngHide.
<span ng-click="toggle=!toggle">
<span ng-show="toggle">☐</span>
<span ng-hide="toggle">☑</span>
Some text with the checkbox here
</span>
You don't need to use jQuery, use ngClass, to change the classes according to what a variable holds
<checkbox ng-click="value = !value">
<span class="fa" ng-class="{'fa-square-o': !value , 'fa-check-square-o': value}"></span>
You need ngChecked.
When you change the checkbox, apply your method:
ng-checked="MyMethod()"
The most easiest example:
input type='checkbox' ng-checked='MyMethod()' />
Script:
$scope.MyMethod = function() {
//your logic
return true; //checked
}
i want to know if there is an angular way of binding attribute of a HTML element to the ngModel.
for e.g. I have two HTML element and I want to change the widh of other element if the width of first element changes..I thought there will be some way to bind width property of first element to a model property and then using the same model to set the width of other element.
HOW to do this scenario angular way.
Could be like...
<div ng-style="{'width':firstWidth}">
</div>
<div ng-style="{'width':secondWidth}">
</div>
And some controller code that is similar to...
$scope.firstWidth = 100 + "px";
$scope.secondWidth = $scope.firstWidth;
Then somewhere change first width and notice that second width would automatically change. In essence. I don't know if this is the best way as there are many ways to do this but here is the simplest.
Example for comments
<div ng-style="{'width':size}">
</div>
<div ng-style="{'width':size}">
</div>
$scope.size = Whatever number your controller is giving you for this dynamic size
ok if i get you, the thing you wanna do is watch the width css property of a div that can dinamicly change it size have you try a watcher with function for that:
$scope.da_width = {};
$scope.elem = angular.element('div#first'); //jquery need it for this
$scope.$watch(function($scope) {return $scope.elem.css('width'); }, function(newValue) {
$scope.da_width = { 'width': newValue };
});
this way youll always know what is the width of div#first and can be assigned to lets say div#two in your view or something:
<div id="two" ng-style="da_width">...</div>
I'm trying to show div depends on permission of log in user.
<div class="container">
<p> {{permission}}</p>
<div ng-show="permission" class="admin_panel">
....
</div>
</div>
and in controller, it is set:
$scope.init = function(){
if($window.sessionStorage.isAdmin){
$scope.permission = $window.sessionStorage.isAdmin;
}
$log.info("are you admin??? " + $scope.permission);
};
$scope.init();
In console, I could verify that permission was set to false and {{permission}} also showed
its value is false. However, ng-show is still showing even though the value is false. I'm not sure what's wrong with this.
Have you tried ng-show="permission === true;"? ng-show, to my understanding, is meant to evaluate whatever is inside the quotes. this would just explicitly state the evaluation. I've had experiences where just having a variable inside the quotes isn't an evaluation that ng-show recognizes for some odd reason.
I had a similar problem except that my variable was changed inside
a timeout function like this:
<div ng-show="check"> something .... </div>
setTimeout(function(){
check = false;
},500);
the problem was solved when i added $scope.$apply() inside timeout:
setTimeout(function(){
check = false;
$scope.$apply()
},500);
If you want to show or hide some content that depends of the user permissions, instead of using "ng-show", you should use "ng-if".
ng-show/ng-hide only adds or remove a CSS class that show or hide that element (display:none), but an user could change it easily in the browser.
Using ng-if: "If the expression assigned to ngIf evaluates to a false value then the element is removed from the DOM, otherwise a clone of the element is reinserted into the DOM."
https://docs.angularjs.org/api/ng/directive/ngIf
I have a same problem and every thing work fine except ng-show. I missed something stupid. when you call a controller from different part of your document you can not share data between them. for example i have 2 div tag
in document
<div id="1" ng-controller="contentCtrl">
<div ng-click="toggleSidebarShow()">
<!-- some code here -->
</div>
</div>
<div id="2" ng-controller="contentCtrl">
<div ng-show="showSidebar">
</div>
</div>
showSidebar between contentCtrl of div 1 and div2 wasn't share.
in controller
// some code
$scope.showSidebar = true;
$scope.toggleSidebar = function (){
$scope.showSidebar = ! $scope.showSidebar;
};
but this code doesn't work because toggleSidebar called outside of the div2 tag and have it's own showSidebar. To conquer this problem you had to use service or modules. see this link to more information.
One more thing to check is when your page loads, in the inspect element check if the element you are trying to use ng-show on is rendered inside the element which has the ng-controller directive.
If your element with ng-show is outside the ng-controller element then ng-show wont work
I have an issue where knockout.js 2.0 isn't showing my item when a CSS style is applied to it. It won't update the display with the style applied to it. If it is off it works.
CSS
.success { display:none }
HTML
<div data-bind="visible: site.signUp.success()" class="success">
Thanks for signining up. You will recieve an email from us in the near future.
</div>
JS
app.viewModel.site.signUp.success(true);
In the period of time before Knockout.js applies bindings, you can prevent the initial rendering/flashing effect by setting the default display style to none.
<div style="display: none" data-bind="visible: site.signUp.success">
Thanks for signining up. You will recieve an email from us in the near future.
</div>
I created a fiddle that shows how you can use the css binding in Knockout to do this. http://jsfiddle.net/johnpapa/vwcfT/
Here is the HTML:
Success Flag: <input type="checkbox" data-bind="checked:site.signUp.success"></input>
<div data-bind="visible: site.signUp.success" >
Thanks for signining up. You will recieve an email from us in the near future.
</div>
<br/><br/>
<span data-bind="text:site.signUp.success"></span>
<div data-bind="css: { success: site.signUp.success}" >
Thanks for signining up. You will recieve an email from us in the near future.
</div>
The first DIV in the example just uses the visible binding, since you dont really need a css class to do this. The second DIV in the example binds to a css class named "success" if the site.signUp.success observable is true. This is more verbose than the first, but could be useful if you needed your css class to do more than just set visibility.
Hope this helps.
Here is the javascript:
var viewModel = {
site: {
signUp: {
success: ko.observable(true)
}
}
};
ko.applyBindings(viewModel);
That's because the success style is defined as display:none, which is equivalent to visible = false. Your CSS class is cancelling out your site.signUp.success() call.
If you want your DIV to show up only when site.signUp.success() == true, just do this:
<div data-bind="visible: site.signUp.success">
Thanks for signining up. You will recieve an email from us in the near future.
</div>
It might be a bit late but I found the following useful. Instead of fixing every element with a visibility control, just wrap a div around all your pre-hidden elements as follow:
<div style="display:none" data-bind="visible: true">
Some pre-hidden elements
<div data-bind="visible: myVisibleFoo">...</div>
<div data-bind="visible: myVisibleBar">...</div>
Other pre-hidden elements
...
</div>
The whole section of elements is hidden initially and is only shown after KO has applied bindings. I usually wrap the whole page with it to avoid any flashing problem.
Just run into this myself; I can see why the did it this way, but it is handy to set a default visibility of none on late loaded elements on the page so they don't flash as scripts are loaded. The nicest way I could find of doing this was just to create a simple custom binding:
ko.bindingHandlers.forceVisible = {
update:
function(el, f_valueaccessor, allbindings, viewmodel, bindingcontext)
{
if(ko.unwrap(f_valueaccessor()))
el.style.display = 'inherit';
else
el.style.display = 'none';
}
};
You have to be a little bit careful when setting up your styles; if you are using a div and your CSS sets it to display:inline-block then this code will not work - it will have block display when the inherit is applied. This simple solution was fine for my use case, however.