How to add and remove div with posts between table rows angularjs ? - angularjs

I have a table with staff are represented as a table. I would like by click on item show list with comments for current employee with input below to support adding new comment.
In my directive I try to write a new element or delete all of the depends on state flag. When I decide to support many comments I made a sophisticated code with open\closed tags and my dataset inside them. I do this because I would like to have an id for container which can be found a deleted with all children like this:
var feedback = document.getElementById(id);
feedback.remove();
But when angular create and add my element (which is made open) in the output it is closed automatically and all my dataset are represented such as nest elements. Below I show just a simplified example what I have right now:
var closeTag = angular.element(
'<div>' +
'<input id="name" type="text" ng-model="feedbackValue" ng-minlength="1" required>' +
'<input add-new-team type="submit" value="Add new feedback">' +
'</div>' +
'</td>' +
'</tr>' +
'</div>'
);
return {
restrict: 'A',
controller: function($scope, $element, $attrs) {
$scope.state = 'off';
$scope.toggle = function() {
$scope.$apply(function() {
console.log($element.children().length);
var name = $element.children()[0].attributes["data-value"].value;
var feedbackSet = teamSharedObj.feedback[name];
var id = "feedBackFor" + name.replace(/\s+/g, '');;
var openTag = angular.element(
'<div id=' + id + '>' +
'</tr><tr>' +
'<td colspan="4">'
);
$compile(openTag)($scope);
$element.after(openTag);
$scope.state = ($scope.state === 'on' ? 'off' : 'on');
if ($scope.state === "on") {
console.log("Feedback " + feedbackSet);
if (typeof feedbackSet === "undefined") {
var noFeedback = angular.element(
'<div id="feedbackContainer">' +
"No information. Does he work on any project?" +
'</div>'
);
$compile(openTag)($scope);
$element.after(openTag);
$compile(noFeedback)($scope);
openTag.after(noFeedback);
$compile(closeTag)($scope);
noFeedback.after(closeTag);
return;
}
// // TODO show all feed rows, setup id as a name
} else {
// TODO destroy a div container as a name
console.log("state is off");
var feedback = document.getElementById(id);
feedback.remove();
}
});
};
this.getState = function() {
return $scope.state;
};
},
link: function( scope, element, attrs ) {
element.bind('click', function() {
scope.toggle();
});
}
The question is how to show and maintain collection of elements from directive dynamically and how to delete them? Do you now simpler or more natural way for angular to do that?

Related

google-place autocomplete directive does not work when its used twice on a single page

I am using a google-place directive to fill the location. The directive I am using is mentioned below:
app.directive('googlePlaces', function(){
return {
restrict:'E',
replace:true,
scope: {location:'='},
template: '<input id="google_places_ac" name="google_places_ac" type="text" class="form-control area_input transition" />',
link: function($scope, elm, attrs){
if(attrs.city =='cities'){
var options = {
types: ['(cities)'],
componentRestrictions: {country: 'IN'}
}
}
else{
var options = {
componentRestrictions: {country: 'IN'}
}
}
var autocomplete = new google.maps.places.Autocomplete($("#google_places_ac")[0], options);
google.maps.event.addListener(autocomplete, 'place_changed', function() {
var place = autocomplete.getPlace();
if(attrs.city =='cities'){
$scope.location = $("#google_places_ac")[0].value + '"' +place.geometry.location.lat() + '"' + place.geometry.location.lng();
}
else{
$scope.location = place.geometry.location.lat() + ',' + place.geometry.location.lng();
}
$scope.$apply();
});
}
};
});
<google-places class="form-control location_field" location="location" city='cities' latlngs = "latlngs" ng-model="chosenPlace"></google-places>
But since I need to use it two times on a single page, the second directive does not work, i.e. it does not show autocomplete results.
Could anyone please help me fix this issue. Help would be much appreciated.
Thanks a lot for the reply.. I solved the issue, by replacing id(#google_places_ac) with 'elm[0]', where 'ele' is the element parameter passed in the link function, it refers to current element.

Ionic + Angular ng-click not bind function from dynamic html element

I have an ion-list and I create each ion-item from a select statment. The ion-item tag has a ng-click event that call a modal window but it never call the show() method from controller. For test I put a static ion-item without DOM modification and it works well.
This is the code:
Modal controller
function uib_w_27_modal_controller($scope, $ionicModal) {
$scope.modal = $ionicModal.fromTemplate($(".uib_w_27").html(), {
scope: $scope,
animation: 'slide-in-up'
});
$scope.show = function() {
$scope.modal.show();
};
$scope.close = function() {
$scope.modal.hide();
};
//Cleanup the modal when we're done with it!
$scope.$on('$destroy', function() {
$scope.modal.remove();
});
// Execute action on hide modal
$scope.$on('modal.hidden', function() {
// Execute action
});
// Execute action on remove modal
$scope.$on('modal.removed', function() {
// Execute action
});
};
Dynamic element
function getFarmaciasSelect(tx, result){
var elem = '';
for (var i = 0; i < result.rows.length; i++) {
var row = result.rows.item(i);
elem += '<ion-item class="item widget uib_w_24 d-margins item-avatar item-icon-right" data-uib="ionic/list_item_avatar" data-ver="0">' +
'<img src="images/Strabburg.jpg">' +
'<h2>' + row['nombre'] + '</h2>' +
'<p>' + row['calle'] + ' ' + row['altura'] + '</p>' +
'<a href="tel:' + row['fijo'] + '"style="text-decoration:none;color:#4CAF50" >' + row['fijo'] + '</a>' +
'<i class="icon ion-plus-circled ion" uib-icon-position="right" ng-controller="uib_w_27_modal_controller" ng-click="show()" data-email="email#email.com"></i>' +
'</ion-item>';
console.log(elem);
}
$('#farmacias-list').html(elem);
}
Thanks for help!
If you really need to keep generating in your code then you need compile your content before add to '#farmacias-list'
$('#farmacias-list').html($compile(elem)($scope));
but even it work, I will recommend you to use collection-repeat to generate content in angular context.

Transcluding nested directive gets rendered twice

I have created two directives, one for simple text-input box (apt-field), one for bootstrap panel with tabbed-view (apt-panel-with-tab).
Here is the Plunker link:
http://plnkr.co/edit/CsxOWGXVzkQugdmpdMyl
In the code, you will see I have used apt-field alone which works just fine, and other within apt-panel-with-tab directive in which apt-field directive gets rendered twice.
I have tried it with both Angular 1.4.8 and 1.5.0-rc.0 and the same result.
Would anyone have any clue what I have been doing wrong? Or could this be a bug in AngularJS?
PS:
SO does not allow me to put plunker link without accompanying code, so here is a portion of the code available on the plunker site:
app.directive('aptField', [
function() {
var directiveObject = {
restrict: 'E',
compile: function(elem, attrs) {
var tpl = null;
var bindTo = null;
if (attrs.field) {
bindTo = 'formData.' + attrs.field;
if (angular.isDefined(attrs.modelBase)) {
bindTo = attrs.modelBase + '.' + attrs.field;
if (bindTo.indexOf('.') == 0) {
bindTo = bindTo.substr(1);
}
}
}
var control = {
tag: 'input',
attrs: {
type: 'text',
class: 'form-control'
},
selfClose: true,
formify: true
};
var tpl = '<' + control.tag;
for (var attr in control.attrs) {
tpl += ' ' + attr + '="' + control.attrs[attr] + '"';
}
tpl += control.selfClose ? ' />' : '></' + control.tag + '>';
var $tpl = angular.element(tpl);
if (bindTo) {
$tpl.attr('data-ng-model', bindTo);
}
elem.append($tpl);
}
};
return directiveObject;
}
]);
Thanks.

Is it okay to have $compile inside the link part of a directive?

I am using AngularJS v1.4.1 and I have the following directive. It was I thought working but now for some reason when my page loads the directive gets called twice. I checked everything I could but I cannot see anything different from before to now except the directive no longer works. Specifically what happens is it appears to be getting called twice.
app.directive('pagedownAdmin', ['$compile','$timeout', function ($compile, $timeout) {
var nextId = 0;
var converter = Markdown.getSanitizingConverter();
converter.hooks.chain("preBlockGamut", function (text, rbg) {
return text.replace(/^ {0,3}""" *\n((?:.*?\n)+?) {0,3}""" *$/gm, function (whole, inner) {
return "<blockquote>" + rbg(inner) + "</blockquote>\n";
});
});
return {
require: 'ngModel',
replace: true,
scope: {
modal: '=modal'
},
template: '<div class="pagedown-bootstrap-editor"></div>',
link: function (scope, iElement, attrs: any, ngModel) {
var editorUniqueId;
if (attrs.id == null) {
editorUniqueId = nextId++;
} else {
editorUniqueId = attrs.id;
}
scope.showPagedownButtons = function () {
document.getElementById("wmd-button-bar-" + editorUniqueId).style.display = 'block';
};
var newElement = $compile(
'<div>' +
'<div class="wmd-panel">' +
'<div data-ng-hide="modal.wmdPreview == true" id="wmd-button-bar-' + editorUniqueId + '" style="display:none;"></div>' +
'<textarea ng-click="showPagedownButtons()" data-ng-hide="modal.wmdPreview == true" class="wmd-input" id="wmd-input-' + editorUniqueId + '">' +
'</textarea>' +
'</div>' +
'<div data-ng-show="modal.wmdPreview == true" id="wmd-preview-' + editorUniqueId + '" class="pagedownPreview wmd-panel wmd-preview"></div>' +
'</div>')(scope);
// iElement.html(newElement);
iElement.append(newElement);
var hide = function () {
document.getElementById("wmd-button-bar-" + editorUniqueId).style.display = 'none';
}
var editor = new Markdown.Editor(converter, "-" + editorUniqueId, {
handler: hide
});
// var $wmdInput = iElement.find('#wmd-input-' + editorUniqueId);
var $wmdInput = angular.element(document.getElementById("wmd-input-" + editorUniqueId));
var init = false;
editor.hooks.chain("onPreviewRefresh", function () {
var val = $wmdInput.val();
if (init && val !== ngModel.$modelValue) {
$timeout(function () {
scope.$apply(function () {
ngModel.$setViewValue(val);
ngModel.$render();
});
});
}
});
ngModel.$formatters.push(function (value) {
init = true;
$wmdInput.val(value);
editor.refreshPreview();
return value;
});
editor.run();
}
}
}]);
Here is the code that calls the directive:
<textarea data-pagedown-admin
data-modal="cos"
id="contentText"
name="contentText"
ng-minlength="5"
ng-model="cos.content.text"
ng-required="true"></textarea>
When I debug the directive by putting a breakpoint on "var editorUniqueId" then I see it goes there twice.
Does anyone have any ideas what might be happening?
I have done this in the past without issue:
var newElement = '<div>' +
// ... more HTML ...
'</div>';
iElement.append( $compile(newElement)(scope) );

Angularjs How to push the new value for the scope object once it is used in the directives

I want to push the new values for my main scope object through the directives.
please advise me how to do that.
In my sample I am using $scope.saveNew function for this but it is not working.
it throw the error "Error: $scope.users is undefined"
myApp.directive("userName", function() {
var editorTemplate = '<td class="click-to-edit">' +
'<div ng-hide="view.editorEnabled">' +
'Add New' +
'</div>' +
'<div ng-show="view.editorEnabled">' +
'<input ng-model="newValue.name">' +
'<input ng-model="newValue.phone">' +
'Save' +
' or ' +
'cancel.' +
'</div>' +
'</td>';
return {
restrict: "A",
template: function(element, attrs) {
if(attrs.type=='add'){
return editorTemplate;
}
else{
return editorTemplate1;
}
},
scope: {
value: "=userName"
},
controller: function($scope) {
$scope.view = {
editableValue: $scope.value,
editorEnabled: false
};
$scope.enableEditor = function() {
$scope.view.editorEnabled = true;
$scope.view.editableValue = $scope.value;
};
$scope.disableEditor = function() {
$scope.view.editorEnabled = false;
};
$scope.save = function() {
$scope.value = $scope.view.editableValue;
$scope.disableEditor();
};
$scope.saveNew = function() {
$scope.users.push({name:$scope.newValue.name,phone:$scope.newValue.phone});
$scope.disableEditor();
};
}
};
});
That's because $scope.users was not defined.
Before pushing objects into it, you should initialize it outside saveNew function:
$scope.users = [];
You are creating an isolated scope through scope: { .. }. This means that your directive's scope wont' prototipically inherit from the parent scope. There are two fixes to this situation:
First solution:
If you think that your directive should be isolated, pass users to your directive as you do for userName.
Second solution:
If you wish to access the parent's scope users variable, set scope to true. However, be aware that every instance of your directive will share the same users object/array.

Resources