Angular: Please turn on my light so I can see - javascript

I want to toggle my 2 on & off images when I click on my lightbulb. Sometimes it seems to work and other times it does not. I cant get the ng-click to work at all unless I use ng-repeat and at least two images. How do I best accomplish toggling the images for 1 lightbulb? Is there any way to synchronize the checkbox so that when it is checked the light goes on and when it is off the light goes off? (I am new to javascript)Here's the fiddle:
Fiddle
<body ng-app="myApp">
<div ng-controller="MyCtrl">
lightbulb is {{state}} <input type="checkbox" ng-model=
"state" ng-true-value="on" ng-false-value="off">
<div ng-repeat="image in images">
<a ng-click="toggleImage(image)">
<img ng-src="{{image.imgUrl}}" />
</a>
</div>
</div>
function MyCtrl($scope) {
//$scope.checkboxState = "off";
//$scope.resetUrl = 'http://www.w3schools.com/js/pic_bulboff.gif';
$scope.state = "on";
$scope.onUrl = 'http://www.w3schools.com/js/pic_bulbon.gif';
$scope.offUrl = 'http://www.w3schools.com/js/pic_bulboff.gif';
$scope.images = [
{imgUrl: 'http://www.w3schools.com/js/pic_bulboff.gif'},
{imgUrl: 'http://www.w3schools.com/js/pic_bulbon.gif'},
];
$scope.toggleImage = function (image) {
if (image === $scope.offUrl) {
image.imgUrl = $scope.onUrl;
} else {
image.imgUrl = $scope.offUrl;
}
};
}

The easiest way to toggle something is to store the state in your scope and then render based on that. Right now you have a lot of extraneous code that could be eliminated. I would restructure your code to something like:
function MyCtrl($scope) {
$scope.onUrl = "pic_bulbon.gif";
$scope.offUrl = "pic_bulboff.gif";
$scope.isBulbOn = false;
$scope.bulbText = function() { return $scope.isBulbOn ? "on" : "off"; };
$scope.bulbUrl = function() {
return $scope.isBulbOn ? $scope.onUrl : $scope.offUrl;
};
}
<body ng-app="myApp">
<div ng-controller="MyCtrl">
lightbulb is {{ bulbText() }}
<input type="checkbox" ng-model="isBulbOn">
<a ng-click="isBulbOn = !isBulbOn">
<img ng-src="{{ bulbUrl() }}" />
</a>
</div>
</body>
You can check out the Fiddle here: http://jsfiddle.net/UYaLJ/

There was an issue with the ifcondition. The ng-repeat works on the JSON object. Hence, the function parameter 'image' is an object. The correct if statement is as follows:
if (image.imgUrl === $scope.offUrl) {
I have updated the fiddle. URL is:http://jsfiddle.net/7857c/1/

Related

How to get element by id which is dynamically created by ng-repeat in angularjs

I am only posting the necessary code and solving this much will clear rest of my doubts. I am new to angularjs, so kindly forgive if I am asking something stupid.
I am using ng-repeat to generate a list which uses an array defined in the controller scope. When I click on 'Add Another' button, a new element is created. I want to get access of this element to add a class to it. But when I use 'getElementById' function in the same function 'addNewForm' I get 'null'.
However, when I call function 'fn' by hitting 'Find Untitled' button, I get the correct element. Could anybody explain and solve this? Any help is appreciated. Thanks in advance!
I am posting the code below:
HTML:
<div ng-controller="myctrl3">
<ul id ="menu_Ul">
<li ng-repeat="x in list">
<button id="{{ 'navAppsButtonID-' + $index }}">{{x}}</button>
<br>
</li>
<li>
<button ng-click="addNewForm()">Add another</button>
</li>
</ul>
<button ng-click="fn()">Find Untitled</button>
</div>
JS:
.controller("myctrl3", function($scope) {
var list = ['abcd', 'efgh', 'ijkl', 'mnop'];
$scope.list = list;
$scope.abc = function () {
var listPush = function () {
$scope.list.push("Untitled Menu");
for(var i = 0;i<$scope.list.length-1;i++) {
var element = document.getElementById('navAppsButtonID-'+i);
element.classList.remove('current');
}
};
var listLen = $scope.list.length;
if($scope.list[listLen-1] === undefined) {
listPush();
}
else if ($scope.list[listLen-1] == "Untitled Menu") {
alert("Cannot open more than one Untitled Menu at the same time.");
}
else {
listPush();
}
};
$scope.addNewForm = function() {
$scope.abc();
console.log("Element is: ", document.getElementById('navAppsButtonID-'+($scope.list.length-1)));
};
$scope.fn = function () {
console.log("Element is: ", document.getElementById('navAppsButtonID-'+($scope.list.length-1)));
};
})
You're thinking too much jQuery and too little angular. If the goal is to add a class to the last element of ng-repeat, this is how you do that:
<li ng-repeat="x in list">
<button ng-class="{ current: $last }">{{ x }}</button>
</li>
$last is a variable available inside ng-repeat, and if it's true, ng-class will set the class current on the element.
You don't assign unique ids to elements to getElementById from somewhere else when working in angular.

Displaying a boolean value in an angularjs grid column

I am working on a web app and I need to display if something is being backed up or not and want to start off by just displaying a boolean value in the column.
Right now, this is some of what I have:
JS:
$scope.backupStatus = false;
$scope.enableBackup = function() {
$scope.selectedProject.backupStatus = true;
};
$scope.disableBackup = function() {
$scope.selectedProject.backupStatus = false;
};
HTML:
<div class="ui-grid-cell-contents">
<div layout="row" layout-align="start center">
<span>{{selectedProject.backupStatus}}</span>
</div>
</div>
Obviously, what I have right now is not working and nothing is being displayed in the column. I am just wondering what conventions I need to follow to get this to display in the column.
To clarify: The enableBackup and DisableBackup functions are being called when there is a button that is clicked in a different part of my grid
I believe the confusion is it isn't immediately clear that you are using ui-grid. I suggest clearing that up / adding the 'angular-ui-grid' tag.
This should work:
<div class="ui-grid-cell-contents">
<div layout="row" layout-align="start center">
<span>{{ grid.appScope.selectedProject.backupStatus }}</span>
</div>
</div>
You have to initialize $scope.selectedProject
$scope.selectedProject = {};
$scope.selectedProject.backupStatus = false;
$scope.enableBackup = function() {
$scope.selectedProject.backupStatus = true;
};
$scope.disableBackup = function() {
$scope.selectedProject.backupStatus = false;
};

checking string value in ng-if statement

I would like to check the value of the property of an object and would like to check the data of string to compare.
<div ng-if="results.dataType === 'textTable'">
This text belongs in a table.
</div>
So far all the divs appear with the text in the body where only two divs should display it.
Is there anything wrong with my ng-if statement and string comparison?
Here is the demo Jsfiddle
Js code
var app = angular.module('myApp', []);
app.controller('ctrl', function($scope) {
$scope.results = {
dataType: 'textTable'
};
$scope.flag = true;
// for testing purpose
$scope.toggle = function() {
if ($scope.flag) {
$scope.results = {
dataType: 'textTable'
};
$scope.flag = !$scope.flag;
} else {
$scope.results = {
dataType: 'textTableNot'
};
$scope.flag = !$scope.flag;
}
}
});
HTML
<div ng-app='myApp'>
<div ng-controller='ctrl'>
<div ng-if='results.dataType === "textTable"'> This text belongs in a table.</div>
{{results.dataType}}
<button ng-click='toggle()'>
Toggle
</button>
</div>
</div>
Hope this will resolve your problem
I realized that in angular 2 the if statement is: *ngIf and not ng-if.
Hope this will resolve your problem.
<div>
<input type="hidden" ng-model="myVar" ng-init="myVar = 'stringformat'">
<div ng-if="myVar =='stringformat'">
<h1>Welcome</h1>
<p>Welcome to my home.</p>
</div>
</div>

How to show the object in an AngularJS ng-repeat loop, only if its nested image exists?

My AngulaJS driven frontend gets the data from a local JSON file and will later switch to an API. The data is a list of Project objects with nested lists of Image objects. I'm displaying this data in a loop:
<div id="projects" ng-app="portfolio">
<div id="projectsList" ng-controller="ProjectsListController as projectsList">
<div class="projectItem" ng-repeat="projectItem in projectsList.projectsListData._embedded.projects">
<div class="project-image">
<img
ng-src="{{projectItem._embedded.images[0].src}}"
title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
/>
</div>
</div>
</div>
</div>
But sometimes the image src is invalid (error 404). It would be better to skip such projects, where the first image (images[0]) cannot be found. How to make the script skip the irrelevant objects?
EDIT
I've already got three answers, but the solutions don't work and I want to explain the problem exactly:
The src property of the images is alwys set. It's not the problem. That means, that checking if it's set or not (like ng-show="projectItem._embedded.images[0].src != ''" or ng-if="{{projectItem._embedded.images[0].src}}") will not work -- cannot work.
It doesn't work -- the src property is set. It's wrong (will cuase the 404 error), but it's set and projectItem._embedded.images[0].src != '' will return true for the "irrelevant" objects as well.
This is a hacky way of making this work:
To avoid loading images when they throw 404 error or when the images are invalid,
This must be inside your controller. This function checks whether the image URL is valid/invalid.
$scope.imageExists = function(image, object, index) {
var img = new Image();
img.onload = function() {
object[index] = true;
$scope.$apply();
};
img.onerror = function() {
return false;
};
img.src = image;
};
Now in View:
I'm initiating an object called img={}; in the ng-repeat.
Then initializing the value for that index in ng-repeat to $scope.imageExists function. Inside that function, on success of that image load, am setting img[index]= true.
<div ng-repeat="image in images" ng-init="img = {}">
<img ng-src="{{image}}" ng-init="img[$index] = imageExists(image, img, $index)" ng-show="img[$index]">
</div>
DEMO
So applying it to your code:
<div id="projects" ng-app="portfolio">
<div id="projectsList" ng-controller="ProjectsListController as projectsList">
<div class="projectItem" ng-repeat="projectItem in projectsList.projectsListData._embedded.projects" ng-init="img = {}">
<div class="project-image" ng-init="img[$index] = imageExists(projectItem._embedded.images[0].src, img, $index)" ng-show="img[$index]">
<img
ng-src="{{projectItem._embedded.images[0].src}}"
title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
/>
</div>
</div>
</div>
</div>
Place the $scope.imageExists code from above to your controller.
You can use ng-if
<div class="projectItem" ng-repeat="projectItem in projectsList.projectsListData._embedded.projects" ng-if="{{projectItem._embedded.images[0].src}}">
<div class="project-image">
<img
ng-src="{{projectItem._embedded.images[0].src}}"
title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
/>
</div>
</div>
</div>
Or you can also use ng-show/ng-hide which just doesn't show the element but would be present in DOM.
But be careful when you use ng-if as it creates its own scope.
EDIT: If the url is already set then one way is to test if the url exists using this method (or anything like this) JavaScript/jQuery check broken links , and
ng-if="UrlExists(projectItem._embedded.images[0].src)"
<div class="project-image" ng-if="projectItem._embedded.images[0].src != ''">
<img
ng-src="{{projectItem._embedded.images[0].src}}"
title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
/>
</div>
You could create your own image directive:
<my-image src="http://someimageurl"></my-image>
If the image exists, the directive will insert the image into the DOM. If it does not, then you can ignore it, or insert a message.
var app = angular.module('app', []);
app.directive('myImage', function() {
return {
restrict: 'E',
replace:true,
link: function(scope, element, attr) {
var image = new Image();
image.onload = function() {
element.append(image);
}
image.onerror = function() {
element.html('Something went wrong or the image does not exist...');
}
image.src = attr.src;
}
}
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<my-image src="https://www.google.ca/images/srpr/logo11w.png" />
<my-image src="https://server/images/doesnotexist.png" />
</div>

Angularjs - How to 'ng-repeat' a div for 'value in ng-model'-times?

Using Angularjs, I want to create say 10 <div> if user inputs '10' in a text box.
<input type="text" id="gcols" placeholder="Number of Columns" ng-model="cols"/>
So whatever value user enters in this box, those many shall be created. So my generalized question is, how to 'ng-repeat' a <div> for 'ng-model' times?
UPDATE:
Appreciating for all of your answers, I did something like following, by referring your answers. And that is working as of now, but tell me if any other logic is more efficient than this.
$scope.divs = new Array();
$scope.create=function(){ //I added a button & invoked this function on its ng-click
var a = $scope.cols;
for(i=0;i<a;i++)
{
$scope.divs.push(a);
}
alert($scope.divs);
};
You need to create an array to iterate on it.
In your controller:
app.controller('ctrl', function ($scope) {
$scope.cols = 0;
$scope.arr = [];
$scope.makeArray = function () {
$scope.arr.length = 0;
for (var i = 0; i < parseInt($scope.cols) ; i++) {
$scope.arr.push(i);
}
}
});
In your view:
<div ng-controller="ctrl">
<input ng-model="cols" type="text" ng-change="makeArray()" />
<div ng-repeat="o in arr">hi</div>
</div>
JSFiddle
DEMO: http://jsfiddle.net/JsFUW/
In your module/app/controller
$scope.cols =4; /* a default */
$scope.divs =[]; /* whatever these are */
In the template
<input type="text" id="gcols" placeholder="Number of Columns" ng-model="cols"/>
<div ng-repeat="div in divs | limitTo:cols" >
...
</div>
As comment question , try this :
In the controller
$scope.cols
In the template
<input type="text" id="gcols" placeholder="Number of Columns" ng-model="cols"/>
<h3>cols: {{cols}} </h3>
Do you see that value change on the page as you type ? If not your $scope.cols is not in the template scope.
In your view:
<input ng-model="cols" ng-change="colsChanged()"/>
<div ng-repeat="item in items track by $index">{{$index}} {{item}}</div>
In your controller:
app.controller('MyCtrl', function($scope) {
$scope.cols = 0;
$scope.colsChanged = function () {
$scope.items = new Array(+$scope.cols);
};
//optional: if you're starting with 1 or more "cols"
$scope.colsChanged();
});
Alternatively, you could roll your own directive that used transclusion to repeat itself multiple times, but that could get involved and probably isn't going to gain you much.

Categories

Resources