I am having one chart directive created, and I am bootstrpping the app after loading google api. In following code, a simple data table is working fine. But when I load data from server in async manner, chart is not being displayed.
Controller
'use strict';
myNetaInfoApp.controller('allCandidatesController', [
'$scope','allCandidates2009Svc', '$timeout',
function ($scope, allCandidates2009Svc, $timeout) {
$scope.data1 = {};
$scope.data1.dataTable = new google.visualization.DataTable();
$scope.data1.dataTable.addColumn("string", "Party");
$scope.data1.dataTable.addColumn("number", "qty");
$scope.data1.dataTable.title = "ASDF";
$timeout( function (oldval, newval) {
allCandidates2009Svc.GetPartyCriminalCount().then(function(netasParty) {
var i = 0;
for (var key in netasParty) {
$scope.data1.dataTable.addRow([key.toString(), netasParty[key]]);
i++;
if (i > 20) break;
}
});
});
$scope.dataAll = $scope.data1;
//sample data
$scope.data2 = {};
$scope.data2.dataTable = new google.visualization.DataTable();
$scope.data2.dataTable.addColumn("string", "Name");
$scope.data2.dataTable.addColumn("number", "Qty");
$scope.data2.dataTable.addRow(["Test", 1]);
$scope.data2.dataTable.addRow(["Test2", 2]);
$scope.data2.dataTable.addRow(["Test3", 3]);
}
]);
Service
'use strict';
myNetaInfoApp.factory('allCandidates2009Svc', ['$http', '$q',
function ($http, $q) {
var netas;
return {
GetPartyCriminalCount: function () {
var deferred = $q.defer();
$http.get('../../data/AllCandidates2009.json')
.then(function (res) {
netas = res;
if (netas) {
var finalObj = {};
_.each(netas.data, function(neta) {
finalObj[neta.pty] = finalObj[neta.pty] ? finalObj[neta.pty] + 1 : 1;
});
deferred.resolve(finalObj);
}
});
return deferred.promise;
}
};
}]);
Directive
"use strict";
var googleChart = googleChart || angular.module("googleChart", []);
googleChart.directive("googleChart", function () {
return {
restrict: "A",
link: function ($scope, $elem, $attr) {
var dt = $scope[$attr.ngModel].dataTable;
var options = {};
if ($scope[$attr.ngModel].title)
options.title = $scope[$attr.ngModel].title;
var googleChart = new google.visualization[$attr.googleChart]($elem[0]);
$scope.$watch($attr.ngModel, function (oldval, newval) {
googleChart.draw(dt, options);
});
}
};
});
HTML
<div ng-controller="allCandidatesController">
<div class="col-lg-6">
<h2>Parties and Candidates with Criminal Charges</h2>
<div google-chart="PieChart" ng-model="dataAll" class="bigGraph"></div>
<!--<p><a class="btn btn-primary" href="#" role="button">View details »</a></p>-->
</div>
<div class="col-lg-6">
<h2>Heading</h2>
<div google-chart="BarChart" ng-model="data2" class="bigGraph"></div>
</div>
</div>
I think you need to wrap your function body in allCandidates2009Svc factory with scope.$apply(). But the return deferred.resolve() will be outside scope.$apply().
function asyncGreet(name) {
var deferred = $q.defer();
setTimeout(function() {
// since this fn executes async in a future turn of the event loop, we need to wrap
// our code into an $apply call so that the model changes are properly observed.
scope.$apply(function() {
deferred.notify('About to greet ' + name + '.');
if (okToGreet(name)) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
});
}, 1000);
return deferred.promise;
}
Read the docs here
http://docs.angularjs.org/api/ng.$q
Related
I’ve been playing around with Upload file - Streaming method. The original code, here:
https://github.com/aspnet/Docs/tree/master/aspnetcore/mvc/models/file-uploads/sample/FileUploadSample
However, I’m trying to get the data in the value attribute of <input value=” ”> using Angular, the idea is that I can POST the value into my MVC model instead of whatever is typed by the user (as in the original code). So, I have done this change to the input value property.
Streaming/Index.cshtml:
<div ng-app="myApp">
<div ng-controller="myCtrl">
..
<input value="#Model.name” type="text" name="Name" ng-model="name"/>
..
<button ng-click="createUser()">Create User</button>
..
</div>
</div>
#section scripts{
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="~/js/app.js"></script>
}
However, with Angular code running under app.js, the following piece of code actually fails with status code 400. This is because the passed value is “” and not the data under of value attribute of the HTML input tag.
App.js:
var User = (function () {
function User(name) {
this.name = name;
}
return User;
}());
var myApp = angular.module('myApp', []);
myApp.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function (scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function () {
scope.$apply(function () {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
myApp.service('userService', ['$http', function ($http) {
this.createUser = function(user) {
var fd = new FormData();
fd.append('name', user.name);
return $http.post('/streaming/upload', fd, {
transformRequest: angular.identity,
headers: {
'Content-Type': undefined
}
});
};
}]);
myApp.controller('myCtrl', ['$scope', 'userService', function ($scope, userService) {
$scope.createUser = function () {
$scope.showUploadStatus = false;
$scope.showUploadedData = false;
var user = new User($scope.name);
userService.createUser(user).then(function (response) { // success
if (response.status == 200) {
$scope.uploadStatus = "User created sucessfully.";
$scope.uploadedData = response.data;
$scope.showUploadStatus = true;
$scope.showUploadedData = true;
$scope.errors = [];
}
},
function (response) { // failure
$scope.uploadStatus = "User creation failed with status code: " + response.status;
$scope.showUploadStatus = true;
$scope.showUploadedData = false;
$scope.errors = [];
$scope.errors = parseErrors(response);
});
};
}]);
function parseErrors(response) {
var errors = [];
for (var key in response.data) {
for (var i = 0; i < response.data[key].length; i++) {
errors.push(key + ': ' + response.data[key][i]);
}
}
return errors;
}
The solution must be a simple one, but after much research, I haven’t been able to find out how to modify it to make the data in the value=’’” attribute being passed across. This might be a stupid question but a headache for me however since I’m a total newbie regarding Angular. Please have some mercy, help.
Thanks
Use the ng-init directive to initialize the model:
<input ng-init="name= #Model.name" type="text" name="Name" ng-model="name"/>
Im trying to complete this custom filter to filter a list of all "savings" created in the last 24 hours
Controller filter
angular.module('savings').filter('lessThan', function () {
return function(savings, requirement) {
var filterKey = Object.keys(requirement)[0];
var filterVal = requirement[filterKey];
var filtered = [];
if(filterVal !== undefined && filterVal !== ''){
angular.forEach(savings, function(saving) {
var today = new Date();
var date = new Date(saving.created.$date); <-- Unresolved variable $date
alert(date);
var diff = today - date;
diff = diff / (1000*60*60);
if(diff < filterVal) {
filtered.push(saving);
}
});
return filtered;
}
return savings;
};
});
And here is how i call it from the view
<div ng-repeat="saving in savings | orderBy: '-votesreal' | limitTo:6 | lessThan: {'created.$date':24}" class="col-lg-2 no-padding-spotlight text-center">
<div class=" thumbnail-spotlight thumbnail centred-image">
<img src="{{saving.image}}" /><br>
<a class="text-center" ng-href="/savings/{{saving._id}}" ng-bind="saving.title +' (€'+ saving.price +' # '+ saving.retailer+')'"></a>
</div>
</div>
Ive wrote a note where the unresolved variable is. How do i declare the "saving" object which is coming from the database. Without the filter it returns all results fine.
Controller Code
angular.module('savings').controller('SavingsController', ['$scope', '$timeout', '$stateParams', '$location', '$window', 'Authentication', 'Savings', 'FileUploader',
function($scope, $timeout, $stateParams, $location, $window, Authentication, Savings, FileUploader) {
$scope.authentication = Authentication;
$scope.user = Authentication.user;
$scope.savingImageURL = '/modules/users/client/img/profile/saveme-placeholder.png';
// $scope.user.imageURL = '/modules/users/client/img/profile/saveme-placeholder.png';
$scope.imageURL1 = '';
$scope.hottestsorted = true;
$scope.newestsorted = true;
$scope.brandLogo = '/modules/users/client/img/profile/argos-logo.png';
$scope.spotlightSort = Savings.votesreal;
$scope.savings = Savings;
//$scope.user.imageURL = '';
$scope.submitFormSaving = function(isValid) {
$scope.submitted = true;
};
}
]);
Client.service
//Savings service used for communicating with the savings REST endpoints
angular.module('savings').factory('Savings', ['$resource',
function ($resource) {
return $resource('api/savings/:savingId', {
savingId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
]);
Well it's good to see that $scope.savings has snuck in there. Try something like this:
Instead of $scope.savings = Savings; use:
Savings.query({}, function(resp){
console.log(resp);
$scope.savings = resp;
});
If your api endpoint needs the savingId use:
Savings.query({ savingId: [something] }, function(resp){
console.log(resp);
$scope.savings = resp;
});
This should work for you.
This is the scenario :
<export-team>
<ul>
<li>
<button buy-ticket="{{data}}" buy-callback="onBuyTicket()">buy</button>
</li>
<li>
<button buy-ticket="{{data}}" buy-callback="onBuyTicket()">buy</button>
</li>
</ul>
</export-team>
The buyTicket directive
(function() {
'use strict';
angular
.module('myApp')
.directive('buyTicket', buyTicket);
/** #ngInject */
function buyTicket($parse, ngDialog, authService, APPCONFIG, $rootScope, shareToken, contestsFactory, shareCurrentTicket, shareIdSession, shareSessionAAMS, $location) {
var vm = this;
var directive = {
restrict: 'A',
link : function(scope, element, attributes) {
var buyCompatible = attributes['buyCompatible'];
function addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
var buyTicket = function(contest) {
var d = new Date();
var y = d.getFullYear();
var m = addZero(d.getMonth()+1);
var day = addZero(d.getDate());
var h = addZero(d.getHours());
var min = addZero(d.getMinutes());
var s = addZero(d.getSeconds());
var date = ''+y+m+day+h+min+s+'';
var transactionId = $rootScope.TRANSACTIONID;
var currentTOKEN = shareToken.get();
var data = {
idSessione:currentTOKEN, // ->TOKEN
userAgent:navigator.userAgent,
sessioneAAMS:contest.aams_session_id,
gameId:APPCONFIG.GAME_ID,
transactionId:transactionId,
dateTime:date,
buyIn:contest.buy_in
}
var dialogLoading = ngDialog.open({
closeByDocument : false,
closeByEscape : false,
showClose : false,
id : 'ft-modal-loading',
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/loading.html';
$scope.title = 'Acquisto Ticket';
$scope.error = 'Il sistema sta procedendo all\'acquisto del ticket';
}]
});
contestsFactory.buyTicket(data).success(function(response){
dialogLoading.close();
if (response.esito == "0") {
if (!buyCompatible) {
shareCurrentTicket.set(response.ticketSogei);
shareSessionAAMS.set(contest.aams_session_id);
shareIdSession.set(contest.id_session);
$location.path('my-contests/'+contest.id_contest+'/'+contest.contest_status);
}
} else {
var message = response.descrizione;
var ids = ngDialog.getOpenDialogs();
var dialogError = ngDialog.open({
id : "ft-modal-error-2",
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/error.html';
$scope.title = 'Errore';
$scope.error = message;
}]
});
}
})
.error(function(){
var dialogErrorNotEndled = ngDialog.close('ft-modal-loading');
ngDialog.open({
id : 'ft-modal-error',
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/error.html';
$scope.title = 'Errore';
$scope.error = 'Il servizio non è attualmente disponibile';
}]
});
})
}
var openConfirmBuyTicket = function(contest) {
contest = JSON.parse(contest);
if (ngDialog.isOpen('ft-modal-contest-detail')) {
ngDialog.close('ft-modal-contest-detail');
};
if (!authService.isLogged()) {
ngDialog.open({
controller: ['$scope', function($scope){
$scope.bodyUrl = 'app/components/modals/body/not_logged.html';
$scope.title = 'Spiacenti';
$scope.error = 'Devi essere loggato per poter partecipare ad un contest';
}]
});
} else {
ngDialog.openConfirm({
controller: ['$scope', function($scope){
$scope.title = 'CONFERMA';
$scope.bodyUrl = 'app/components/modals/body/confirm_buy.html';
$scope.contest_name = contest.name_contest;
$scope.buy_in = contest.buy_in;
$scope.currency = APPCONFIG.CURRENCY_SYMBOL;
}],
}).then(function (confirm) {
buyTicket(contest);
}, function(reject) {
});
}
}
element.on('click', function(e){
var contest = attributes['buyTicket'];
openConfirmBuyTicket(contest);
})
}
};
return directive;
}
})();
The export directive
(function() {
'use strict';
angular
.module('myApp')
.directive('exportTeam', exportTeam);
/** #ngInject */
function exportTeam(contestsFactory, ngDialog, APPCONFIG, formatDateFactory) {
var vm = this;
var directive = {
restrict: 'AE',
transclude: true,
controller : function($scope) {
$scope.test = function() {
alert('hey');
}
},
link : function(scope, element, attributes) {
element.on('click', function(e){
var ticket = attributes['exportTeam'];
var id_session = attributes['idsession'];
scope.openExportTeamDialog(ticket, id_session, false);
})
scope.openExportTeamDialog = function(ticket, aams_session_id, afterSave) {
ngDialog.open({
id : 'ft-modal-exportTeam-detail',
className : 'ngdialog ngdialog-theme-default ft-dialog-exportTeam',
controller: ['$scope', 'contestsFactory', 'APPCONFIG', function($scope, contestsFactory, APPCONFIG){
$scope.title = "Aggiungi contest compatibili";
$scope.bodyUrl = 'app/components/modals/body/exportTeam.html';
$scope.contentLoading = true;
$scope.currency = APPCONFIG.CURRENCY_SYMBOL;
$scope.afterSave = afterSave;
$scope.CompatibleContests = [];
contestsFactory.getCompatibleContests(ticket).then(function(response){
angular.forEach(response.data[0], function(item, i){
var multientryOptions = [];
if(item.multientry > 1) {
item.isMultientry = false;
var n = parseInt(item.multientry);
for (i = 1; i <= n; i++) {
multientryOptions.push({
text : i+" team",
value : i
})
}
item.multientryOptions = multientryOptions;
item.multientryOptionSelected = multientryOptions[0];
}else{
item.isMultientry = true;
};
})
$scope.CompatibleContests = response.data[0];
$scope.contentLoading = false;
})
}]
});
}
scope.openExportTeamDialog('N3E94100A725F9QG', 'M3E921013C6DCFCT', false);
}
};
return directive;
}
})();
The buy-ticket directive makes an http call, on the response i want to be able to call the onBuyTicket method of the <export> directive.
I'm trying to understand the best way to do that.
Thanks everyone
This sample show to you how can call an function from your directive
In this sample you can see we just insert data in our directive, and then we handle the data and other action in the directive.
var app = angular.module("app", []);
app.controller("ctrl", function ($scope) {
$scope.dataFromYourController = [
{ name: "Concert Jennifer", value: 200 },
{ name: "007", value: 100 }
];
})
.directive("export", function () {
var template = "<div>" +
"<ul>" +
"<li ng-repeat=\"array in arrays\">" +
"<button ng-click=\"onBuyTicket()\">buy Ticket {{array.name}}</button><hr>" +
"</li>" +
"</ul>" +
"</div>";
return {
restrict: "E",
template: template,
scope: {
data: "="
},
link: function (scope, elem, attrs, ngModel) {
scope.arrays = scope.data;
scope.onBuyTicket = function () {
alert("calling function from directive");
}
}
};
})
<!doctype html>
<html ng-app="app" ng-controller="ctrl">
<head>
</head>
<body>
<h1>call action from your directive</h1>
<export data="dataFromYourController"></export>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</body>
</html>
#eesdil
var directive = {
restrict: 'AE',
transclude: true,
controller : function($scope) {
$scope.onBuyTicket = function() {
alert('hey');
}
}
}
Ho can I call that from the buy-ticket directive ?
Use the $parent
<button buy-ticket="{{data}}" buy-callback="$parent.onBuyTicket()">buy</button>
So the expor directive something like:
var directive = {
restrict: 'AE',
template: '<ng-tansclude></ng-transclude>',
transclude: true,
controller : function($scope) {
$scope.onBuyTicket = function() {
alert('hey');
}
}
}
UPDATED:
see the plunker:
https://plnkr.co/edit/fmyJ4oPLvTiI0TzO7h1b?p=preview
It really depends what you can call and what you cannot based on the scopes... here if you would remove the scope from the export directive would work without the $parent also as export would share the same scope as the parent (main view)
The best way to communicate events from a child directive to a parent directive (or controller) is to use the $emit method of the scope.
What you want to do is take an ng-click event, get additional information with an $http call, and $emit an event with the additional information to be used by your parent directive (or controller).
HTML
<button buy-ticket="data" ng-click="onBuyTicket()">buy</button>
The directive:
angular.module("myApp").directive("buyTicket", function($http) {
function linkFn(scope,elem,attrs) {
scope.onBuyTicket = function() {
var buyData = scope.$eval(attrs.buyTicket);
var url = someFunction(buyData);
$http.get(url).then (function (response) {
var httpData = response.data;
scope.$emit("buyTicket.click", buyData, httpData);
});
};
};
return {
restrict: "AE",
link: linkFn
};
});
In the parent controller:
$scope.$on("buyTicket.click", function (buyData, httpData) {
console.log(buyData);
console.log(httpData);
});
Notice that I used the $eval method to get the data from the variable named by the buy-ticket attribute.
When choosing a name for the event, I recommend including the name of the directive in the event's name. It makes it clear the source of the event and is unlikely to be duplicated elsewhere.
I'm writing an app with Ionic and the $cordovaSQLite plugin. I have this simple controller
.controller('TopicCtrl', ['$scope', '$stateParams', 'Topic', function($scope, $stateParams, Topic) {
$scope.topic = null;
Topic.get($stateParams.topicId).then(function(data) {
$scope.topic = data;
});
}]);
for this simple view
<ion-view view-title="{{topic.title}}">
<ion-content>
...
</ion-content>
</ion-view>
The problem is $scope.topic remains null the first time I display this view (therefore no title for this view is displayed), when I navigate to another view and then press the back button $scope.topic has the fetched data so the topic's title is displayed on the view. Why is $scope.topic not updated as expected?
My services.js looks like this
.factory('SQLiteService', ["$q", "$interval", "$cordovaSQLite", "$ionicPlatform", function($q, $interval, $cordovaSQLite, $ionicPlatform) {
var self = this;
self.db = null;
self.init = function() {
window.plugins.sqlDB.copy("database.db", function () {
self.db = window.sqlitePlugin.openDatabase({name: "database.db", bgType: 1, createFromLocation: 1, location: 2});
}, function (e) {
self.db = window.sqlitePlugin.openDatabase({name: "database.db", bgType: 1, createFromLocation: 1, location: 2});
});
};
self.query = function(query, bindings) {
var wrapper = function() {
bindings = typeof bindings !== 'undefined' ? bindings : [];
var deferred = $q.defer();
$ionicPlatform.ready(function () {
$cordovaSQLite.execute(self.db, query, bindings).then(function(data) {
deferred.resolve(data);
}, function(error) {
deferred.reject(error);
});
});
return deferred.promise;
};
if (!self.db) {
var q = $q.defer();
$interval(function() {
if (self.db) {
q.resolve();
}
}, 100, 25);
return q.promise.then(function() {
return wrapper();
});
}
return wrapper();
};
self.fetch = function(data) {
return data.rows.item(0);
};
return self;
}])
.factory('Topic', ["SQLiteService", function(SQLiteService) {
var self = this;
self.get = function(id) {
var query = "SELECT id, title FROM topics WHERE id = ?";
return SQLiteService.query(query, [id]).then(function(data) {
return SQLiteService.fetch(data);
});
}
return self;
}]);
i had same issue, i solved by using alternative directives for view title as
<ion-view cache-view="false">
<ion-nav-title>{{topic.title}}</ion-nav-title>
<ion-content>
...
</ion-content>
and make sure cache is off for this view
How can I force angularjs to reload an image with an ng-src attribute, when the url of the image has not changed, but its contents has?
<div ng-controller='ctrl'>
<img ng-src="{{urlprofilephoto}}">
</div>
An uploadReplace service that performs a file upload, is replacing the content of the image, but not the url.
app.factory('R4aFact', ['$http', '$q', '$route', '$window', '$rootScope',
function($http, $q, $route, $window, $rootScope) {
return {
uploadReplace: function(imgfile, profileid) {
var xhr = new XMLHttpRequest(),
fd = new FormData(),
d = $q.defer();
fd.append('profileid', profileid);
fd.append('filedata', imgfile);
xhr.onload = function(ev) {
var data = JSON.parse(this.responseText);
$rootScope.$apply(function(){
if (data.status == 'OK') {
d.resolve(data);
} else {
d.reject(data);
}
});
}
xhr.open('post', '/profile/replacePhoto', true)
xhr.send(fd)
return d.promise;
}
}
}]);
When the uploadReplace returns, I don't know how I can force the image to reload
app.controller('ctrl', ['$scope', 'R4aFact', function($scope, R4aFact){
$scope.clickReplace = function() {
R4aFact.uploadReplace($scope.imgfile, $scope.pid).then(function(){
// ?? here I need to force to reload the imgsrc
})
}
}])
An easy workaround is to append a unique timestamp to ng-src to force image reload as follows:
$scope.$apply(function () {
$scope.imageUrl = $scope.imageUrl + '?' + new Date().getTime();
});
or
angular.module('ngSrcDemo', [])
.controller('AppCtrl', ['$scope', function ($scope) {
$scope.app = {
imageUrl: "http://example.com/img.png"
};
var random = (new Date()).toString();
$scope.imageSource = $scope.app.imageUrl + "?cb=" + random;
}]);
Perhaps it could be as simple as adding a decache query string to the image URL? ie.
var imageUrl = 'http://i.imgur.com/SVFyXFX.jpg';
$scope.decachedImageUrl = imageUrl + '?decache=' + Math.random();
This should force it to reload.
An "angular approach" could be creating your own filter to add a random querystring parameter to the image URL.
Something like this:
.filter("randomSrc", function () {
return function (input) {
if (input) {
var sep = input.indexOf("?") != -1 ? "&" : "?";
return input + sep + "r=" + Math.round(Math.random() * 999999);
}
}
})
Then you can use it like this:
<img ng-src="{{yourImageUrl | randomSrc}}" />
Try This
app.controller('ctrl', ['$scope', 'R4aFact', function($scope, R4aFact){
$scope.clickReplace = function() {
R4aFact.uploadReplace($scope.imgfile, $scope.pid).then(function(response){
$scope.urlprofilephoto = response + "?" + new Date().getTime(); //here response is ur image name with path.
});
}
}])
I resorted to make a directive to put random param in the src, but only if the image changes, so I don't mess that much with the caching.
I use it to update the user's profile pic in the navbar when they update it via AJAX, which doesn't happen that often.
(function() {
"use strict";
angular
.module("exampleApp", [])
.directive("eaImgSrc", directiveConstructor);
function directiveConstructor() {
return { link: link };
function link(scope, element, attrs) {
scope.$watch(attrs.eaImgSrc, function(currentSrc, oldSrc) {
if (currentSrc) {
// check currentSrc is not a data url,
// since you can't append a param to that
if (oldSrc && !currentSrc.match(/^data/)) {
setSrc(currentSrc + "?=" + new Date().getTime());
} else {
setSrc(currentSrc);
}
} else {
setSrc(null);
}
})
function setSrc(src) { element[0].src = src; }
}
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="exampleApp">
<div>
<img ea-img-src="src"></img>
</div>
<button ng-click="src = 'http://placehold.it/100x100/FF0000'">IMG 1</button>
<button ng-click="src = 'http://placehold.it/100x100/0000FF'">IMG 2</button>
<button ng-click="src = 'http://placehold.it/100x100/00FF00'">IMG 3</button>
</div>