Why is AngularJs not rendeting directive on page change? - javascript

I found this treeview directive
////////////////////////////////////////////////////////////////////////////////
/// TREEVIEW //////////////////////////////////////////////////////////////////
angular.module('myApp.treeView', []).directive('treeView', function($compile) {
return {
restrict : 'E',
scope : {
localNodes : '=model',
localClick : '&click'
},
link : function (scope, tElement, tAttrs, transclude) {
var maxLevels = (angular.isUndefined(tAttrs.maxlevels)) ? 10 : tAttrs.maxlevels;
var hasCheckBox = (angular.isUndefined(tAttrs.checkbox)) ? false : true;
scope.showItems = [];
scope.showHide = function(ulId) {
var hideThis = document.getElementById(ulId);
var showHide = angular.element(hideThis).attr('class');
angular.element(hideThis).attr('class', (showHide === 'show' ? 'hide' : 'show'));
}
scope.showIcon = function(node) {
if (!angular.isUndefined(node.children)) return true;
}
scope.checkIfChildren = function(node) {
if (!angular.isUndefined(node.children)) return true;
}
/////////////////////////////////////////////////
/// SELECT ALL CHILDRENS
// as seen at: http://jsfiddle.net/incutonez/D8vhb/5/
function parentCheckChange(item) {
for (var i in item.children) {
item.children[i].checked = item.checked;
if (item.children[i].children) {
parentCheckChange(item.children[i]);
}
}
}
scope.checkChange = function(node) {
if (node.children) {
parentCheckChange(node);
}
}
/////////////////////////////////////////////////
function renderTreeView(collection, level, max) {
var text = '';
text += '<li ng-repeat="n in ' + collection + '" >';
text += '<div class="wrapper-treeview" style="padding: 10px" ng-class="{bgFirsr: $first && showIcon(n), bgChildren: !showIcon(n), bgBrown: !$first && showIcon(n), lastBorderRadius: $last}" >';
text += '<span ng-show=showIcon(n) class="show-hide" ng-click=showHide(n.id)><i class="zmdi zmdi-plus icon-color"></i></span>';
text += '<span ng-show=!showIcon(n) style="padding-right: 13px"></span>';
// if (hasCheckBox) {
// text += '<input class="tree-checkbox" type=checkbox ng-model=n.checked ng-change=checkChange(n)>';
// }
text+= '<span class="icon-color" style="cursor: pointer" ng-click=localClick({node:n})><i class="zmdi zmdi-eye"></i></span>'
text += '<label style="vertical-align: bottom;">{{n.name}}</label></div>';
if (level < max) {
text += '<ul ng-class="{show: $first && showIcon(n), hide: !$first && showIcon(n)}" id="{{n.id}}" class="" ng-if=checkIfChildren(n)>'+renderTreeView('n.children', level + 1, max)+'</ul></li>';
} else {
text += '</li>';
}
return text;
}// end renderTreeView();
try {
var text = '<ul class="tree-view-wrapper">';
text += renderTreeView('localNodes', 1, maxLevels);
text += '</ul>';
tElement.html(text);
$compile(tElement.contents())(scope);
}
catch(err) {
tElement.html('<b>ERROR!!!</b> - ' + err);
$compile(tElement.contents())(scope);
}
}
};
});
And i call it in the html in this way
<tree-view id="treeview" checkbox click="myClick(node)" class="ng-cloak" model="nodes"></tree-view>
if i refresh the page with F5 i can see everything ok. But if I change page of the website and i click again the page of the treeview doesn't work. It doesn't render the directive. There are no errors on the console. I tried to add ng-cloak directive and class but nothing changed

Related

html not appending to the carousel on popover

I Am Trying to make a popover with a bootstrap carousel and where the carousel items are to be generated and appended from a script but I get the carousel but I am unable to append the item. I tried hard but I didn't come up with a solution.
the HTML initialized is as below
HTML:
<div class="popup" data-popup="popup-1">
<div class="popup-inner">
<i class="fas fa-bars"></i>
<div class="frame">
<div id='carousel' class='carousel slide' data-bs-ride='carousel'>
<div class='carousel-inner items-slider1'>
</div>
</div>
</div>
</div>
</div>
the script I have tried was
Javascript:
function findallchord(currentchord , currenttype) {
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord ,currenttype,i)) {
Raphael.chord("div3", Raphael.chord.find(currentchord , currenttype,i), currentchord +' ' +currenttype).element.setSize(75, 75);
}
}
}
var getChordRoots = function (input) {
if (input.length > 1 && (input.charAt(1) == "b" || input.charAt(1) == "#"))
return input.substr(0, 2);
else
return input.substr(0, 1);
};
$('.popup').on('shown.bs.popover', function () {
$('.carousel-inner').carousel();
});
$('[data-bs-toggle="popover"]').popover({
html: true,
content: function() {
return $('.popup').html();
}}).click(function() {
var oldChord = jQuery(this).text();
var currentchord = getChordRoots(oldChord);
var currenttype = oldChord.substr(currentchord.length);
findallchord(currentchord , currenttype);
var chordsiblings = $('#div3').children().siblings("svg");
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord , currenttype,i)) {
var itemid = "chord" + i;
var theDiv = "<div class='carousel-item"+((itemid=="chord1") ? ' active':'')+" ' id='"+currentchord+''+itemid+"'> "+chordsiblings[i-1].outerHTML+" </div>";
$('.items-slider1').append(theDiv);
}
}
});
I have also tried appendTo also as
$(theDiv).appendTo('.items-slider1');
Please Help to solve this
This is the output I get, the appended elements are not in the carousel
Note: I am using Bootstrap 5
Try instantiating the carousel after you've set it up
/*
$('.popup').on('shown.bs.popover', function () {
$('.carousel-inner').carousel();
});
*/
$('[data-bs-toggle="popover"]').popover({
html: true,
content: function() {
return $('.popup').html();
}}).click(function() {
var oldChord = jQuery(this).text();
var currentchord = getChordRoots(oldChord);
var currenttype = oldChord.substr(currentchord.length);
findallchord(currentchord , currenttype);
var chordsiblings = $('#div3').children().siblings("svg");
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord , currenttype,i)) {
var itemid = "chord" + i;
var theDiv = "<div class='carousel-item"+((itemid=="chord1") ? ' active':'')+" ' id='"+currentchord+''+itemid+"'> "+chordsiblings[i-1].outerHTML+" </div>";
$('.items-slider1').append(theDiv);
}
}
$('.carousel-inner').carousel();
});
It was needed to do call the click function first before popover as below
$('[data-bs-toggle="popover"]').click(function() {
var oldChord = jQuery(this).text();
var currentchord = getChordRoots(oldChord);
var currenttype = oldChord.substr(currentchord.length);
findallchord(currentchord , currenttype);
var chordsiblings = $('#div3').children().siblings("svg");
for (let i = 1; i < 10; i++) {
if (Raphael.chord.find(currentchord , currenttype,i)) {
var itemid = "chord" + i;
var theDiv = "<div class='carousel-item"+((itemid=="chord1") ? ' active':'')+" ' id='"+currentchord+''+itemid+"'> "+chordsiblings[i-1].outerHTML+" </div>";
$('.items-slider1').append(theDiv);
}
}
}).popover({
html: true,
content: function() {
return $('.popup').html();
}});

JavaScript arrays adding last element instead of recently added input

Good evening. I am new to JavaScript and I need help with my mini-project and I have only one issue here and it is in the this.Add = function ().
It works properly when I enter a duplicate value from my list therefore it displays an alert that no dupes are allowed. But... when I enter a unique value, it only adds up the last element present (Wash the dishes) from myTasks list. instead of the one I recently entered and the list goes on adding the same ones. Did I just misplace something?
This is my final activity yet and I want to finish it to move to the next function. Thank you in advance.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Tasks CRUD</title>
<style>
#tasks{
display: none;
}
</style>
</head>
<body>
<center>
<form action="javascript:void(0);" method="POST" onsubmit="app.Add()">
<input type="text" id="add-task" placeholder="Add another card">
<input type="submit" value="Add">
</form>
<div id="tasks" role="aria-hidden">
<form action="javascript:void(0);" method="POST" id="saveEdit">
<input type="text" id="edit-task">
<input type="submit" value="Edit" /> <a onclick="CloseInput()" aria-label="Close">✖</a>
</form>
</div>
<p id="counter"></p>
<table>
<tr>
<th>Name</th>
</tr>
<tbody id="myTasks">
</tbody>
</table>
</center>
<script>
var app = new function() {
this.el = document.getElementById('myTasks');
this.myTasks = ['Clean the bathroom', 'Wash the dishes'];
this.Count = function(data) {
var el = document.getElementById('counter');
var name = 'task';
if (data) {
if (data > 1) {
name = 'Things To DO';
}
el.innerHTML = data + ' ' + name ;
} else {
el.innerHTML = 'No ' + name;
}
};
this.FetchAll = function() {
var data = '';
if (this.myTasks.length > 0) {
for (i = 0; i < this.myTasks.length; i++) {
data += '<tr>';
data += '<td>' + this.myTasks[i] + '</td>';
data += '<td><button onclick="app.Edit(' + i + ')">Edit</button></td>';
data += '<td><button onclick="app.Delete(' + i + ')">Delete</button></td>';
data += '</tr>';
}
}
this.Count(this.myTasks.length);
return this.el.innerHTML = data;
};
this.Add = function () {
el = document.getElementById('add-task');
// Get the value
var task = el.value;
if (task ) {
for(task of this.myTasks)
{
var ctr = 0;
if(document.getElementById("add-task").value == task){
ctr = 1;
break;
}
}
if(ctr == 1)
{
window.alert("Duplicates not allowed.");
}else{
// Add the new value
this.myTasks.push(task.trim());
// Reset input value
el.value = '';
// Dislay the new list
this.FetchAll();
}
}
};
this.Edit = function (item) {
var el = document.getElementById('edit-task');
// Display value in the field
el.value = this.myTasks[item];
// Display fields
document.getElementById('tasks').style.display = 'block';
self = this;
document.getElementById('saveEdit').onsubmit = function() {
// Get value
var task = el.value;
if (task) {
// Edit value
self.myTasks.splice(item, 1, task.trim());
// Display the new list
self.FetchAll();
// Hide fields
CloseInput();
}
}
};
this.Delete = function (item) {
// Delete the current row
this.myTasks.splice(item, 1);
// Display the new list
this.FetchAll();
};
}
app.FetchAll();
function CloseInput() {
document.getElementById('tasks').style.display = 'none';
}
</script>
</body>
</html>
In your for loop:
for (task of this.myTask) {
}
You are not declaring a new task variable, but instead assigning to the outer task variable, hence the repeated addition of tasks already in your list.
You can declare a new variable in the for scope like so:
for (const task of this.myTask) {
}
Your HTML as it is.
And your Javascript goes like below. You have a bug while checking if the task already exists in the array. As you're comparing string value either use simple for loop with triple equals or do as i have attached below.
var app = new function() {
this.el = document.getElementById('myTasks');
this.myTasks = ['Clean the bathroom', 'Wash the dishes'];
this.Count = function(data) {
var el = document.getElementById('counter');
var name = 'task';
if (data) {
if (data > 1) {
name = 'Things To DO';
}
el.innerHTML = data + ' ' + name ;
} else {
el.innerHTML = 'No ' + name;
}
};
this.FetchAll = function() {
var data = '';
if (this.myTasks.length > 0) {
for (i = 0; i < this.myTasks.length; i++) {
data += '<tr>';
data += '<td>' + this.myTasks[i] + '</td>';
data += '<td><button onclick="app.Edit(' + i + ')">Edit</button></td>';
data += '<td><button onclick="app.Delete(' + i + ')">Delete</button></td>';
data += '</tr>';
}
}
this.Count(this.myTasks.length);
console.log(this.myTasks.length);
return this.el.innerHTML = data;
};
this.Add = function () {
el = document.getElementById('add-task');
// Get the value
var task = el.value;
console.log(task);
if (task ){
var arrayContainsTask = (this.myTasks.indexOf(task) > -1);
if(arrayContainsTask == true){
window.alert("Duplicates not allowed.");
}else{
// Add the new value
this.myTasks.push(task);
// Reset input value
el.value = '';
}
// Dislay the new list
this.FetchAll();
}
}
}

Assigning Click Event After Altering innerHTML

Using AngularJS w/ Meteor
Essentially, I have a ng-click event on a which calls a function that clones the and places it elsewhere. I changed some of the innerHTML so that there is a 'x' icon for removing the item. I would like to be able to click that new to remove it.
So, I know that setting an attribute of ng-click does not work. I am stuck on how I can make this happen.
my template addClass.html
<tr id="{{$index}}" ng-repeat="class in $ctrl.classes" ng-click="$ctrl.addThisClass($event)">
<td><span class="badge pull-left">{{class.units}}</span> {{class.name}}</td>
<td>{{class.number}}</td>
<td>{{class.teacher}}<span class="glyphicon glyphicon-plus text-danger pull-right"></span></td>
</tr>
the function it calls
addThisClass = function($event) {
var clone, table, tableBody, tableRow, tableRowLength, cmpTableData, tableData, tableDataText, remove, alert, footer;
clone = $event.currentTarget.cloneNode(true);
table = document.getElementById('queuedClasses');
tableBody = table.getElementsByTagName('tbody')[0];
tableRow = tableBody.getElementsByTagName('tr');
tableRowLength = tableBody.getElementsByTagName('tr').length;
tableData = clone.getElementsByTagName('td');
footer = document.getElementById("modalFooter");
tableDataText = tableData[2].textContent;
if (tableRowLength < 7) {
for (var i = 0; i < tableRowLength; i++) {
if (tableRow[i].getElementsByTagName('td')[1].textContent == tableData[1].textContent) {
if (footer.getElementsByClassName('alert').length === 0) {
alert = document.createElement('div');
alert.className = 'alert alert-danger text-left';
alert.id = 'alertMessage';
alert.setAttribute('role', 'alert');
alert.appendChild(document.createTextNode('Sorry, you already added that class to the queue.'));
footer.insertBefore(alert, footer.childNodes[0]);
setTimeout(function() {
$("#alertMessage").fadeTo(500, 0).slideUp(500, function() {
$(this).remove();
});
}, 3000);
}
return;
}
}
remove = '<span class="glyphicon glyphicon-remove text-danger pull-right" style="padding-top: 2px; !important;" title="Delete Class"></span>';
tableData[2].innerHTML = tableDataText + remove;
tableBody.appendChild(clone);
} else {
if (footer.getElementsByClassName('alert').length === 0) {
alert = document.createElement('div');
alert.className = 'alert alert-danger text-left';
alert.id = 'alertMessage';
alert.setAttribute('role', 'alert');
alert.appendChild(document.createTextNode('You cannot have more than 7 classes queued.'));
footer.insertBefore(alert, footer.childNodes[0]);
setTimeout(function() {
$("#alertMessage").fadeTo(500, 0).slideUp(500, function() {
$(this).remove();
});
}, 3000);
}
}
/* Reset Filter */
var input, filterTable, filterTR;
input = document.getElementById("searchForClasses");
input.value = '';
filterTable = document.getElementById("tableClasses");
filterTR = filterTable.getElementsByTagName("tr");
for (i = 0; i < filterTR.length; i++) {
filterTR[i].style.display = "";
}
}

AngularJS clear model when changing route

I have a filter & search function in my fixed header consisting of dropdown (for filter) and input field (for search).
For the dropdown I'm using this Angularjs-dropdown-multiselect
At the moment, after submitting the request, user will be directed to result page and the model content for dropdown and input text is preserved and that's how I want it to be. The problem is, I want to reset the model (back to empty) if user go to page other than the result page.
HTML:
<div class="col-sm-3">
<div class="dropdown" ng-dropdown-multiselect="" options="cats" selected-model="catModel" checkboxes="true" translation-texts="{buttonDefaultText: 'Categories'}"></div>
</div>
<div class="col-sm-3">
<div class="dropdown" ng-dropdown-multiselect="" options="ccs" selected-model="ccModel" checkboxes="true" translation-texts="{buttonDefaultText: 'Credit Cards'}"></div>
</div>
<div class="col-sm-6">
<form data-ng-submit="findValue(catModel, ccModel, keyword)" >
<div class="input-group search-bar">
<input type="search" class="form-control" placeholder="Search for..." data-ng-model="keyword">
<span class="input-group-btn">
<button class="btn btn-search" type="button" data-ng-click="findValue(catModel, ccModel, keyword)"><img src="img/icon_search.png" alt="Search" /></button>
</span>
<input type="submit" style="position: absolute; left: -9999px; width: 1px; height: 1px;"/>
</div>
</form>
</div>
JS:
.controller('mainController', ['$scope', '$http', '$location', 'dataFactory',
function ($scope, $http, $location, dataFactory){
dataFactory.getCategories().success(function (data){
$scope.cats = data;
});
dataFactory.getCcs().success(function (data){
$scope.ccs = data;
});
$scope.catModel = [];
$scope.ccModel = [];
$scope.findValue = function(catModel, ccModel, keyword) {
var searchUrl = baseUrl;
var catID = '';
if(catModel.length > 0) {
searchUrl += 'categoryID=';
angular.forEach(catModel, function(value, key) {
if(key < catModel.length - 1) {
searchUrl += value.id + ',';
catID += value.id + ',';
} else {
searchUrl += value.id;
catID += value.id;
}
})
if(ccModel.length > 0 | keyword != null) {
searchUrl += '&';
}
}
if(ccModel.length > 0) {
searchUrl += 'ccID=';
angular.forEach(ccModel, function(value, key) {
if(key < ccModel.length - 1) {
searchUrl += value.id + ',';
} else {
searchUrl += value.id;
}
})
if(keyword != null) {
searchUrl += '&';
}
}
if(keyword != null) {
searchUrl += 'search_keyword=' + keyword;
}
$http.get(searchUrl).success(function (data) {
$scope.results = data;
$scope.pageTitle = 'Promotions search result';
$location.path('/promotion');
})
}
}
I'm putting the model and function inside mainController because the header is in every view.
I'm quite new in AngularJS and programming so this code might not be proper, please let me know if there's a simpler and proper way. Any help is appreciated.
Thank you
You can subscribe to the following event $locationChangeSuccess that will be triggered on every location change.
And inside you can reset your model.
Just declare
$rootScope.$on('$locationChangeSuccess', function() {
//reset your model here
});

Input number's value to append div's

Fiddle - http://liveweave.com/enRy3c
Here's what I'm trying to do.
Say my input number is 5. I want to dynamically append 5 divs to the class .enfants. However I haven't figured out how to do that. I been searching and searching and I haven't came across anything.
jQuery/JavaScript:
var counter = 1;
// Value number = .enfants children
$(".ajouter-enfants").on('keyup change', function() {
var yourChildren = "<div>" + counter++ + "</div>";
var CallAppend = function() {
$(".enfants").append( yourChildren );
};
// If 0 or empty clear container
if ( $.inArray($(this).val(), ["0", "", " "]) > -1 ) {
$(".enfants").html("");
// If only add/have 1 div in container
} else if ($(this).val() === "1") {
$(".enfants").html("").append( yourChildren );
// If > 0 add as many divs as value says
} else {
$(".enfants").html("");
CallAppend();
}
});
HTML:
<div class="contenu" align="center">
<div>
Value number = .enfants children
</div>
<input type="number" min="0" class="ajouter-enfants" value="0" />
<div class="enfants">
</div>
</div>
How about a simple loop? If you just want to append, try something like this:
$(".ajouter-enfants").on('change', function() {
var numDivs = $(this).val();
var i;
for (i = 1; i <= numDivs; i += 1) {
$('.enfants').append('<div>' + i + '</div>');
}
});
EDIT:
If you want to replace instead of append the newly-created <div>'s, try something like:
$(".ajouter-enfants").on('keyup change', function() {
var content = '';
var numDivs = $(this).val();
var i;
for (i = 1; i <= numDivs; i += 1) {
content += '<div>' + i + '</div>';
}
$('.enfants').html(content);
});
This will replace the entire content of any elements using the class ajouter-enfants with the number of <div>'s specified in the input box.
Try this:
$(".ajouter-enfants").on('keyup change', function() {
var num = +$.trim($(this).val()), target = $(".enfants"), i = 0, s = '';
target.empty();
if (!isNaN(num) && num > 0) {
for (; i < num; i++) {
s += '<div>' + (i + 1) + '</div>';
}
target.html(s);
}
});
How would you get it to only append the value amount? It appends more when the value is (2 becomes 3, 3 becomes 6, 4 becomes 10 and repeats even when I'm decreasing the numeric value) –
#Michael Schwartz
Here is another code example that might be helpfull.
$(".ajouter-enfants").on('change', function() {
var numDivs = $(this).val();
var i;
var html ='';
for (i = 1; i <= numDivs; i += 1) {
html += '<div>' + i + '</div>';
}
$('.enfants').empty().append(html);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="contenu" align="center">
<div>
Value number = .enfants children
</div>
<input type="number" min="0" class="ajouter-enfants" value="0" />
<div class="enfants">
</div>
</div>

Categories

Resources