ng-click not updating value in ng-repeat - javascript

This is the code:
<div ng-repeat="data in products">
<div class=edit ng-click="dataUI.showEdit = true; content = data;">
</div>
<div ng-repeat="renew in data.renewed">
<div class=edit ng-click="dataUI.showEdit = true; content = renew;">
</div>
</div>
</div>
<div class="modal" ng-show="dataUI.showEdit">
<div class="product_price">{{content.product_price}}</div>
</div>
When I click this, the popup opens but, the content is not filled with items. In the popup, I am using content to show the data.
What am I doing wrong here?
JSFiddle: http://jsfiddle.net/HB7LU/22082/

Here's your fiddle fixed: http://jsfiddle.net/masa671/xtaa9gev/
You were using an old version of Angular, changed to version 1.4.8 (see the JavaScript Gear).
Then, a couple of missing injections:
MyCtrl.$inject = ['$scope'];
myApp.controller('MyCtrl', MyCtrl);
Finally, assignment to content in ng-click did not work, because ng-repeat creates a new scope ("Always use a dot"). I fixed this with dataUI.content. Here is one good explanation: Ng-click doesn't work inside ng-repeat.

Related

How can I copy one element to another with angular legacy?

Lets say I have 2 divs side by side. (for the sake of argument using bootstrap lets say they are both 6 columns each)
If I drag an object into the column on the right, and then click a button below that column, I want the column on the left to mirror the one on the right. (so they are now identical)
I know we can do this with 2 way binding in real time, but I am wondering if it is possible to invoke 2 way binding on a click event? I also looked into angular copy, but there is very little documentation on this that i understand.
<div class="col-sm-12">
<div class="col-sm-6">
<div class="col-sm-12 left_column">
<p>{{master}}</p>
</div>
</div>
<div class="col-sm-6">
<div class="col-sm-8">
<div class="col-sm-12 right_column">{{source}}</div>
<button class="btn btn-primary" ng-click="update()">Submit Changes</button>
</div>
<div class="col-sm-4">
<div class="col-sm-4 drag_item_1"></div>
<div class="col-sm-4 drag_item_2"></div>
<div class="col-sm-4 drag_item_3"></div>
</div>
</div>
angular.module('app', ['ui.router'])
.config(['$urlRouterProvider', '$stateProvider',
function($urlRouterProvider, $stateProvider){
$urlRouterProvider.otherwise('/');
$stateProvider.state('homepage', {
url: "/",
templateUrl: "templates/homepage.html"
})
}])
.controller('swap_ctrl', function(){
$scope.source = "can it work?";
$scope.update = function() {
angular.copy($scope.source, $scope.master);
};
});
I know the code above doesnt work. It was just an attempt at trying to understand angular.copy. But it should give you an idea behind the structure. I was just going to use dragula to handle the dragging of objects to the right column.
I don't know how your actual code looks like, but let's assume you have two arrays that represent your columns:
$scope.columnsLeft = [...];
$scope.columnsRight = [...];
And view markup looks like this:
<div ng-repeat="column in columnsLeft track by $index"></div>
<div ng-repeat="column in columnsRight track by $index" ng-click="copyColumnToTheLeft(column, $index)"></div>
The ng-click could be inside the div element and it could be applied to the button. Then the method copyColumnToTheLeft which will copy our column could look like this:
$scope.copyColumnToTheLeft = function (column, index) {
$scope.columnsLeft[index] = angular.copy(column);
};
Using angular.copy will create a copy of the column passed to the method, so changing the column (in right array) in future will not immediately show the changes on the left panel, since it would be a different object.
Hope this helps.
UPDATE: In your particular case, you are going to have 2 arrays, one is master and second one is source:
$scope.master = [...];
$scope.source = [...];
If you are going to modify source array using dnd then your update method could look like:
$scope.update (){ $scope.master = angular.copy($scope.source); };
Anyway a good example of how it works is on the official docs page.

passing href link through angularjs ng-repeat

I have an array of messages
$scope.messsages = []
Upon clicking a button the content of a text area gets added into the array using ng-click method.This message is used to query the api. After which we get a response from the server which too is added into the array $scope.messages. All these messages are shown in html using ng-repeat i.e:-
<div ng-repeat="msg in messages track by $index">
{{ msg }}
</div>
However if I get a response from the server as a hyperlink string like
To know more click here.
The message that gets displayed in ng-repeat is a plain string with no hyperlinks. It renders the <a href="URL"> part as a string itself. I would like to represent it in html format.
One way it worked was by using
document.getElementById("demo").innerHTML = $scope.messages;
But I would like to know is there any angular way to do so in the ng-repeat part itself.
Thanks in advance
Include ngSanitize module on your app and then change your view as below
<div ng-repeat="msg in messages track by $index">
<div ng-bind-html="msg"></div>
</div>
Try to use like this
<div ng-repeat="msg in messages track by $index">
<div ng-bind-html="msg"></div>
</div>
Here is the plunk example for it.
You should use ng-bind-html for this. so you should inject ngSanitize in your app.
$scope.html = 'test';
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
angular.module('myapp', ['ngSanitize'])
.controller('main', function($scope,$sce) {
$scope.messages = [{"link":"<a href='#/abc'>abc</a>"}];
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular-sanitize.min.js"></script>
<div ng-app="myapp" ng-controller="main">
<div ng-repeat="msg in messages">
<div ng-bind-html="msg.link"></div>
</div>
</div>

angular and isotope - Adding new item within isotope context

UPDATE: After some very insightful code from #Marc Kline, I went back and cleaned up my page. It turned out that I had my controllers listed in reversed (My angular controller was inside the Isotope controller, instead of the other way round). Once I changed it back and cleaned off some additional scripting, it started working again. I have updated the code snippet to reflect the change. Thanks to Marc and S.O!
I am having trouble figuring out how can I add new items using Angular and still let Isotope manage their UI display.
I am using Isotope and Angular to render server results in a masonry style layout. When I add new items to the layout on a button click, angular adds it just fine. However, they do not appear in the context of the isotope UI and appear separately (and cannot be sorted, laid out or filtered using Isotope).
Here is my JS Code
<!-- Define controller -->
var contrl = app.controller("MainController", function($scope){
$scope.items ={!lstXYZ}; //JSON data from server
//Function called by button click
$scope.addItem = function(item)
{
$scope.items.push(item);
$scope.item = {};
}
});
contrl.$inject = ['$scope'];
Here is the HTML to display the server results...(Updated to show working code..refer comments)
<div ng-controller="MainController">
<div class="isotope" id="isotopeContainer">
<div ng-repeat="item in items">
<div class='element-item {{item.status}}' data-category='{{item.status}}'>
<p class="number">{{item.type}}</p>
</div>
</div>
</div>
</div>
And here is my HTML button to add the new items
<table>
<tr>
<td><input type="text" ng-model="item.status" /></td>
</tr>
<tr>
<td><input type="text" ng-model="item.type" /></td>
</tr>
<tr>
<td colspan="2"><input type="Button" value="Add" ng-click="addItem(item)" /> </td>
</tr>
</table>
I am not sure how do I ensure that Isotope can recognize the newly added element and re-animate the layout.
Any help or pointers will be very appreciated. Thanks!
ng-repeat takes care of adding the new element to the DOM for you. However, Isotope isn't doing any "watching" for you - you have to manually invoke a redraw of the container.
You could just add something like $("#isotopeContainer").isotope(...) directly to your controller, but in the spirit of keeping your controllers lean and free of DOM-related code, you should instead create a service. Something like:
myApp.service('Isotope', function(){
this.init = function(container) {
$(container).isotope({itemSelector: '.element-item'});
};
this.append = function(container, elem) {
$(container).isotope('appended', elem);
}
});
... where the first method initializes a new Isotope container and the next redraws the container after an item is appended.
You could then inject this service into any controller or directive, but directives probably are best for this scenario. In this Plunker, I created two new directives: one for Isotope containers and another for Isotype elements, and used the service to do the initialization and redrawing.
In this particular case, my code was not written correctly. I have updated the question's code but wanted to mention it more clearly here...
Apparently, the beauty of Angular is that you do not need to bother with the underlying UI framework (Isotope in this case). As long as you update the Angular data array, the UI binding is updated automatically.
The only gotcha is to ensure that the UI framework div is within the context of your Angular div.
Here is the non-working code...Note that the isotope div is outside the Angular controller.
<div class="isotope" id="isotopeContainer">
<div ng-controller="MainController">
<div ng-repeat="item in items">
<div class='element-item {{item.status}}' data-category='{{item.status}}'>
<p class="number">{{item.type}}</p>
</div>
</div>
</div>
</div>
Here is the updated code with isotope running within the Angular controller context...
<div ng-controller="MainController">
<div class="isotope" id="isotopeContainer">
<div ng-repeat="item in items">
<div class='element-item {{item.status}}' data-category='{{item.status}}'>
<p class="number">{{item.type}}</p>
</div>
</div>
</div>
</div>
Hope this helps. I am thankful for all the responses and help I got from SO. Appreciate the learning opportunity.

Using Waypoints.js inside an AngularJS view

I am trying to use Waypoints inside a scrollable AngularJS view, however it's not working. I am trying to use ui.utils jQuery Passthrough but nothing happens. Here's what I have so far:
<body>
<div id="wrapper">
<div id="nav-menu">
<...>
</div>
<div id="main" class="main">
<div ng-view></div>
</div>
</div>
</body>
I am using the following template for the view:
<div class="fullScreenImage"></div>
<div ui-jq="waypoint" ui-options="test">test</div>
and my controller looks something like this:
app.controller('myController', ['$scope',
function ($scope) {
$scope.test = function(){
alert('You have scrolled to an entry.');
}}]);
My main element is scrollable but the window is not. Setting passthrough to the main div will trigger the test function, however I need it inside the template. Any suggestions?
Providing a JSFiddle or plunkr would be helpful.
But I suppose the issue is because the template is inside ngView.
As the content of the template is placed inside the ngView via XHR, the waypoints needs to be refreshed as discussed in the link http://imakewebthings.com/jquery-waypoints/#doc-refresh
An Angular directive will be more effective IMHO.
I had trouble with waypoints nested in ng-views as well.
My solution was just to wait till after the view had loaded to bind the waypoints, for this you can use $viewContentLoaded.
E.g.
myApp.run(['$rootScope', function($rootScope) {
$rootScope.$on('$viewContentLoaded', function(){
var waypoint = new Waypoint({
element: document.getElementById('waypoint'),
handler: function(direction) {
console.log('Scrolled to waypoint!')
}
})
});
}]);
I had the same problem. It's also possible to delay the binding with $timeout e.g $timeout(addWaypoints());.

AngularJS reusing the same controller on one page, with different configuration

I want to display two elements on a page controlled by different instances of the same controller, but I need to register some external information that will be unique (one "joystick" gets an identifying property set, like "player = one" while the other gets "player = two").I'm not sure of the best way of pulling this off exactly
Here's a generic example of what I'm trying to accomplish:
<!-- These need to have different configurations -->
<div ng-include src="'joystick/joy.tpl.html'"
ng-controller="JoystickCtrl">...</div>
<div ng-include src="'joystick/joy.tpl.html'"
ng-controller="JoystickCtrl">...</div>
Should I:
Use a directive?
<div ng-include src="'joystick/joy.tpl.html'"
ng-controller="JoystickCtrl" player="one">...</div>
<div ng-include src="'joystick/joy.tpl.html'"
ng-controller="JoystickCtrl" player="two">...</div>
Use $injector? (fyi - this might be an incorrect implementation)
<div ng-controller="DualJoyCtrl">
<div ng-include src="'joystick/joy.tpl.html'"
ng-controller="joyOne" player="one">...</div>
<div ng-include src="'joystick/joy.tpl.html'"
ng-controller="joyTwo" player="two">...</div>
</div>
-----
.controller('DualJoyCtrl', function ($injector, JoystickCtrl, $scope, $rootScope) {
$scope.joyOne = $injector.instantiate(JoystickCtrl, {$scope: $rootScope.$new(), player:"one"});
$scope.joyTwo = $injector.instantiate(JoystickCtrl, {$scope: $rootScope.$new(), player:"two"});
});
Or... not do this?
I realize this is similar to another, seemingly inconclusive stack post:
Edit
Since ngController is initialized before ngInit, in order to have data available in controller at once, you should wrap ngController in parent element with ngInit:
<div ng-init="player = 'one'">
<div ng-controller="JoystickCtrl">
...
</div>
</div>
Original answer
I think simple ng-init would suffice:
<div ng-controller="JoystickCtrl" ng-init="player='one'">...</div>
<div ng-controller="JoystickCtrl" ng-init="player='two'">...</div>
Store your config values in a data attribute, and retrieve it within the controller using $attrs. (The AngularJS ngInit documentation recommends to say clear of ng-init unless aliasing special properties of ngRepeat. ) A similar answer is here. This code snippet gives you the general idea:
Index.html:
<div ng-include ng-controller="JoystickCtrl" src="'same.html'" data-id="1"></div>
<div ng-include ng-controller="JoystickCtrl" src="'same.html'" data-id="2"></div>
Controller:
function joystickCtrl($scope, $attrs) {
$scope.id = $attrs.id;
};
View:
<h2>Joystick: {{id}}</h2>
Here is the full code in Plunker.

Categories

Resources