I'm trying to develop a solution through AngularJS where when the user changes the profile image, all other photos based on their profile are also changed.
How can I start developing this feature?
Thanks in advance!
[Solution]
With the help of the #wolfman6377, I can understand the functionality and develop the solution for what I need. I'll leave an example in CodePen.
CodePen
var myApp = angular.module('myApp',[]);
myApp.controller('myController', function() {
this.myVar = 'https://robohash.org/asd'
this.updatePicture = function() {
this.myVar = 'https://angular.io/resources/images/logos/angular/angular.png';
};
});
Thank you, #wolfman6377.
You are using a jQuery-like strategy. jQuery element selector will not be able to change the value of myVar.
I would recommend going through some basic tutorials on angular1. But in a nutshell, you need to:
Do not grab elements and change attributes
add a module to the ng-app value
Use ng-controller in the template
Add ng-click to the button to update the value of myVar
template
<body ng-app="myApp">
<div id="var" ng-controller="myController as vm">
<img ng-src={{vm.myVar}} />
<button ng-click="vm.updatePicture()">Click me</button>
</div>
</body>
controller:
angular
.module('myApp', [])
.controller('myController', function() {
this.myVar = 'https://www.w3schools.com/angular/pic_angular.jpg'
this.updatePicture = function() {
this.myVar = 'https://angular.io/resources/images/logos/angular/angular.png';
};
});
Related
angular-material newbie here. I'm trying to hide some elements in our site using a switch, as instructed by our client. This led me to angular-material's md-switch.
So I tried incorporating it like so...
<md-switch md-no-ink aria-label="switchView" ng-model="switchView">{{switchView}}</md-switch>
And called the value of the switch in my element like this:
<img ng-src="{{photoPath}}" class="profilePic" ng-hide="switchView"/>
After testing it though, it didn't hide my <img> even though my switchView changed its value. Am I missing something here?
Other methods I've tried:
Adding ng-change to my md-switch, which called a function that would equate another variable (e.g. $scope.toggleView = $scope.switchView) with switchView's value. $scope.toggleView would then be used in my ng-hide.
ng-hide = "switchView == true".
Any advice would be very much appreciated. Thank you.
UPDATE 1: To test it, I tried hiding the <div> beside my <md-switch> and it worked perfectly. However it's still not working with my <img>.
Further checking revealed that it was inside a <nav> element. However they're both using the same controller. I wonder if that's the problem? I assumed that it shouldn't be a problem because of this.
The structure is like this:
<nav ng-controller="MainController">
<!-- other navigation elements here -->
<img ng-src="{{photoPath}}" class="profilePic" ng-hide="switchView"/>
</nav>
<div ng-controller="MainController">
<div>Toggle Switch</div>
<md-switch md-no-ink aria-label="switchView" ng-model="switchView">{{switchView}}</md-switch>
</div>
UPDATE 2: I've added the following code in my JS file because there are plans to hide elements in other pages. It still didn't work.
$scope.onChange = function(value) {
$scope.$broadcast("view_mode", $scope.switchView);
}
$scope.$on("view_mode", function(event, switchValue) {
$scope.viewThis= switchValue;
});
My HTML now looks like this:
<img ng-src="{{photoPath}}" class="profilePic" ng-hide="viewThis"/>
As for the controller, ngMaterial was called in a separate JS file (our main), together with all our dependencies and configs. Hence, this wasn't called inside MainController.
mainApp.js
var app = angular.module('myAppModule', [
// other references here
'ngMaterial'
]);
mySample.js
angular
.module('myAppModule')
.controller('MainController', ['$scope', function ($scope) {
// functions etc. go here
Hope this helps clear things up. Thank you.
Try something like this, its a trivial example but hope it helps. Here's a link to working codepen.
There seems to be a couple ways you could handle this according to the docs:
Angular Material- MD-Switch
function exampleController($scope) {
$scope.secondModel = false;
$scope.onChangeEvent = function(value) {
$scope.imgSource = (value) ? 'http://www.fillmurray.com/300/200' : 'http://www.fillmurray.com/g/155/300';
};
// alternatively: you could set the ternary to empty string value here.
}
angular
.module('BlankApp', ['ngMaterial'])
.controller('exampleController', exampleController);
<md-switch ng-model="switchValue" ng-change="onChangeEvent(switchValue)">
<img ng-src="{{imgSource}}" alt="" />
</md-switch>
<md-switch ng-model="secondModel">
<img src="http://www.fillmurray.com/300/200" alt="" ng-hide="secondModel" />
</md-switch>
Thank you to everyone who gave their inputs. After some research, I managed to solve this problem using factories (source).
I'm sharing my solution so that it may help others who experience the same problem.
HTML:
<nav ng-controller="MainController">
<!-- other navigation elements here -->
<img ng-src="{{photoPath}}" class="profilePic" ng-hide="switchView"/>
</nav>
<div ng-controller="MainController">
<div>Toggle Switch</div>
<md-switch md-no-ink aria-label="switchView" ng-model="switchView" ng-change="onChange(switchView)">{{switchView}}</md-switch>
</div>
JS:
angular
.module('myAppModule')
.controller('MainController', ['$scope', 'ViewModeFactory', function ($scope, ViewModeFactory) {
// functions etc. go here
// For client presentation mode
$scope.onChange = function(value) {
ViewModeFactory.setViewMode($scope.switchView);
}
$scope.$watch(function (){
$scope.switchView = ViewModeFactory.getViewMode();
});
}])
.factory('ViewModeFactory', function () {
var data = {isViewMode: ''};
return {
getViewMode: function () {
return data.isViewMode;
},
setViewMode: function(value) {
data.isViewMode = value;
}
};
});
I used factories so that other controllers in our site can use the value passed by md-switch.
Hope this helps.
Have a template that I'd like to load using ng-include and assign a controller instance to. This new template/scope/controller needs to be loaded in response to a user interaction (hover or click).
The content of the template has to be set using element.innerHTML because the content is set by a 3rd party.
The user can then click out of the new div and I would like to destroy the controller/scope that was created.
Pseudocode for what I want to achieve:
popup.setContent("<div ng-controller='PopupController'><div ng-include=\"views/LayerPopup.html\"></div></div>");
How do I tell angular to process the ng-include and ng-controller just as though the page was being loaded for the first time?
Thanks!
Edit:
Add plunker to illustrate question
http://plnkr.co/edit/DPuURCoq2hJ0LCLIN2dc?p=preview
http://jsfiddle.net/ADukg/5420/
Not using ngInclude, but it does fill these criteria:
You pass in a templateURL.
Pass in the name of the controller you would like to use.
Pass in the third party content (which in turn gets set with $element.innerHTML).
Setup a click listener someplace outside the $scope of the popup, which triggers a kill command on the popup.
This is how I imagine you would instantiate it:
<directive tpl="tpl.html"
ctrl="DirectiveController"
third-party-content="{{thirdPartyContent}}">
</directive>
Not sure this will suit you, but I had a fun time putting it together and maybe it'll prove useful to someone else.
In any case, I have to agree with the comments you've recieved so far. It's a bit cryptic as to what you have to work with right now and what possible options are available to you.
Here is a plunker of what you are trying to do. If you click on a button, a popup will show a template, and you can click on the template and it will stay up, but if you click out of it, it will get removed.
HTML
<body ng-controller="MainCtrl" ng-click="closePopup()">
<button ng-click="openPopup($event)" id="clicktarget">Click</button>
<p>Hello {{name}}!</p>
<div ng-include="getPopup()" ng-click="$event.stopPropagation()">
</div>
<script type="text/ng-template" id="theTemplate.html">
<div ng-controller="PopupController">
<div ng-include="'LayerPopup.html'"></div>
</div>
</script>
</body>
JS
angular.module('plunker', [])
.controller('MainCtrl', function($scope, $templateCache) {
$scope.name = 'World';
$scope.popupTmpl = null;
$scope.openPopup = function($event){
$scope.popupTmpl = 'theTemplate.html';
$event.stopPropagation();
};
$scope.getPopup = function(){
return $scope.popupTmpl;
};
$scope.closePopup = function(){
$scope.popupTmpl = null;
};
})
.controller('PopupController', ['$scope', function($scope) {
$scope.aVariableMaybe = 'lulz something';
}]);
On a side note, try to get rid of that JQuery stuff when you are using Angular. Angular can do everything on its own
I have a template like this.
<body ng-app="demo" ng-controller="demo">
<div ng-include="/main.html">
</div>
</body>
And the main.html is.
<div ng-app="main" ng-controller="main>
""
</div>
here is the js.
JS-1
var myapp = angular.module('demo', []);
myapp.controller('demo', function($scope,$routeParams, $route,$http) {
$scope.variable="444"
})
JS-2
var mainapp = angular.module('mainapp', []);
myapp.controller('main', function($scope,$routeParams, $route,$http) {
})
Is it possible to access the scope of JS-1 inside JS-2?, if yes how, if no is there any solution to this.Thanks.
It depend what you want to do.
If you want read $scope.variable variable from JS-1, you should see it in JS-2 $scope.
If you want modify $scope.variable form JS-1, you should create method in JS-1:
$scope.changes = function(data){
$scope.variable = data;
}
This method also should be available in JS-2 $scope.
This isn't nice solution but should work.
The best solution is to create service which will provide operations on JS-1 fields.
I would like to reset the state of my angular app without forcing a page refresh. What's the idiomatic way to do this?
I don't know if there's an idiomatic way, but if you use manual bootstrap (ie, get rid of ng-app), then to reset you could
Remove the element that you bootstrapped angular into
Replace it with a clean copy of the element
Run bootstrap again
Example HTML:
<div id="myid" ng-controller="MyCtrl">
<button ng-click="i = i+1">Add 1</button>
<span>i = {{i}}</span>
<button ng-click="reset()">RESET</button>
</div>
Example controller/JS (with jQuery included as well), which would be run on onload:
var $cleanCopy = $("#myid").clone();
function bootstrap() {
angular.bootstrap(document.getElementById('myid'), ['mymodule']);
}
angular.module('mymodule', []).controller('MyCtrl', function($scope) {
$scope.i = 1;
$scope.reset = function() {
// You need this second clone or angular bootstraps
// into the original clone!
$("#myid").replaceWith($cleanCopy.clone());
bootstrap();
};
});
bootstrap();
Here is a working JSFiddle: http://jsfiddle.net/zd377/2/
in my app I have a wrapper controller that handles some properties dynamically based on other-controllers within it. everything works like a charm if the other-controllers are present/static on load, but as soon as I'm trying to make them dynamic, they stop working.
It was my understanding that the $rootScope is available from everywhere within the app, is that not true?
my JS looks like this:
var webApp = angular.module("webApp",[]);
webApp.controller("ControllerA", function($scope, $rootScope){
$rootScope.cnt = 0;
$rootScope.cntPlusPlus = function(){
$rootScope.cnt++;
};
$rootScope.controllerBs = [];
var template = $(".controller-b").html();
$scope.addControllerB = function(){
$rootScope.controllerBs.push(template);
};
});
webApp.controller("ControllerB", function($scope, $rootScope){
$scope.cntPlusPlus = function(){
console.log("overwrite plus plus");
}
});
Full example: http://plnkr.co/edit/tAcv1F9y7t9q9XsQ1EFL?p=preview
I know that this would be probably better with directives, but is there any way to make it work with Controllers?
thanks for the help
Don't try to access the DOM from controller code. Never. It is very bad practice which breaks AngularJS conventions and eventually provides you with bad architecture. This also means you should not create any DOM elements manually from a controller.
Better to manipulate with the scope itself, not with its visual representation. You can add new models to scope on your button's click, which will be translated to new elements by ng-repeat directive, each with its own controller (remember controllers are instances, not singletons, so that they have separated life cycles).
You might want to make use of <script type="text/ng-template"> and ng-include here instead of hidden divs.
Try to avoid using $rootScope when possible - it is global state which can be dangerous.
It might look like this then (plunker):
HTML:
<div class="controller-a" ng-controller="ControllerA">
Controller A
<div>
<button ng-click="cntPlusPlus()">cnt++</button> CNT: {{cnt}}
</div>
<button ng-click="addB()">Add B</button>
<div ng-repeat="B in Bs">
<div ng-include="'b-template'"></div>
</div>
</div>
<script type="text/ng-template" id="b-template">
<div ng-controller="ControllerB">this is controller b: <button ng-click="cntPlusPlus()">cnt++</button></div>
</script>
JS:
var webApp = angular.module("webApp",[]);
webApp.controller("ControllerA", function($scope){
$scope.cnt = 0;
$scope.cntPlusPlus = function(){
$scope.cnt++;
};
$scope.Bs = [];
$scope.addB = function(){
$scope.Bs.push({});
};
});
webApp.controller("ControllerB", function($scope){
$scope.cntPlusPlus = function(){
console.log("overwrite plus plus");
$scope.$parent.$parent.$parent.cnt++; //should be moved to service
}
});
</script>