AngularJS clear model when changing route - javascript

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
});

Related

display name on html page by clicking on button. The button is generated using data from database

I have a button that is generated using the database information. For example if I insert a name "john" with age 15 into the database, a button with the text "john" along with his age will be generated onto the html page. This is done using appendData function and the buttons are displayed by looping through the data and appending it onto the html page.
I want it as such that if I click on the button with the text "john" I will be displayed the word "john" and 15 on the side.
I tried sending data[i] but its not working. Can someone please help? thank you
<div id="myData" ></div>
<aside>
<p>Details: </p>
<p id="configurationdetails"></p>
</aside>
<script>
fetch('http://localhost:3000/result')
.then(function (response) {
return response.json();
})
.then(function (data) {
appendData(data);
})
.catch(function (err) {
console.log('error: ' + err);
});
function appendData(data) {
var mainContainer = document.getElementById("myData");
for (var i = 0; i < data.length; i++) {
var div = document.createElement("div");
div.innerHTML = '<div class="container"> <div class="solid"> <button id="btn" class="btn" onclick="showinfo('+data[i]+')">' + 'name '+data[i].person_name +data[i].age+ '</button> </div></div>';
mainContainer.appendChild(div);
}
}
function showinfo(info) {
document.getElementById("configurationdetails").innerHTML = info;
}
A quick way to fix it is to not pass the object, but just the value i in the showInfo function:
data = [{person_name:"henk", age:33}, {person_name:"wim", age:34}]
appendData(data)
function appendData(data) {
// save data for later
window.data = data
var mainContainer = document.getElementById("myData");
for (var i = 0; i < data.length; i++) {
var div = document.createElement("div");
div.innerHTML = '<div class="container"> <div class="solid"> <button id="btn" class="btn" onclick="showinfo('+i+')">' + 'name '+data[i].person_name +data[i].age+ '</button> </div></div>';
mainContainer.appendChild(div);
}
}
function showinfo(i) {
document.getElementById("configurationdetails").innerHTML = data[i].person_name + " " + data[i].age;
}
i just created ectra div with id "contentFromUrl" when the page first load and call api so it fills the data in div and when button click it again fetch fills the data.
i provided two cases which one you like you can choose!
<div id="myData" ></div>
<div id="contentFromUrl"></div>
<aside>
<p>Details: </p>
<p id="configurationdetails"></p>
</aside>
<script>
fetch('http://localhost:3000/result')
.then(function (response) {
return response.json();
})
.then(function (data) {
appendData(data);
})
.catch(function (err) {
console.log('error: ' + err);
});
function appendData(data) {
var mainContainer = document.getElementById("myData");
for (var i = 0; i < data.length; i++) {
var div = document.createElement("div");
div.innerHTML = '<div class="container"> <div class="solid"> <button id="btn" class="btn" onclick="showinfo('+data[i]+')">' + 'name '+data[i].person_name +data[i].age+ '</button> </div></div>';
document.getElementById("contentFromUrl").innerHTML = data[i].person_name +data[i].age;
mainContainer.appendChild(div);
}
}
function showinfo(info) {
document.getElementById("configurationdetails").innerHTML = info;
document.getElementById("contentFromUrl").innerHTML = info.person_name + info.age;
}

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();
}
}
}

Why is AngularJs not rendeting directive on page change?

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

Angularjs devade tags when user put comma

I have a case in which I need to divide tags when the user put a comma separation, for the moment the user can only add tags one by one, what I want to do is allows user to enter more than one tag in the input separated by a comma:
This is what I have now :
this is what I want to do :
what I have so far :
<div class="form-group">
<label>Mes centres d'intérêt</label>
<div class="input-group" style="margin-bottom: 8px;">
<input id="tagInsert" type="text" name="newTag" ng-model="newTag" ng-model-options="{debounce: 100}" typeahead="tag for tag in getTags($viewValue)" class="form-control" typeahead-loading="loadingTags" ng-keydown="addInterestOnEvent($event)" ng-disabled="interestLimit" autocomplete="off">
<span class="input-group-btn"><span class="btn btn-primary" ng-click="addInterest()" analytics-on="click" ng-disabled="interestLimit" analytics-event="Ajout Interet" analytics-category="Profil">Ajouter</span></span>
</div>
<p class="form__field__error" ng-show="interestLimit">Vous avez atteint la limite de 10 centres d'intérêt.</p>
<ul class="tags">
<li class="tag" ng-repeat="name in user.interests track by $index">{{ name }} <i class="icon-close" ng-click="removeInterest($index)" analytics-on analytics-event="Supprimer Interet" analytics-category="Profil"></i></li>
</ul>
</div>
My controller :
$scope.getTags = function (name) {
return $http.get('/api/tags/' + name.replace('/', '')).then(function (result) {
var tags = result.data;
for (var i = tags.length; i--; ) {
var tagName = tags[i].name;
if ($scope.user.interests.indexOf(tagName) !== -1) tags.splice(i, 1);
else tags[i] = tagName;
}
return tags;
});
};
$scope.removeInterest = function (id) {
$scope.interestLimit = false;
$scope.user.interests.splice(id, 1);
}
$scope.addInterest = function () {
if ($scope.interestLimit) return;
var element = $document[0].getElementById('tagInsert'),
value = element.value;
if (value.length) {
element.value = '';
if ($scope.user.interests.indexOf(value) === -1) {
$scope.user.interests.push(value);
$scope.interestLimit = $scope.user.interests.length === 10;
}
}
};
$scope.addInterestOnEvent = function (event) {
if (event.which !== 13) return;
event.preventDefault();
$scope.addInterest();
};
$scope.remove = function () {
$scope.confirmModal = Modal.confirm.delete(function () {
User.remove(function () {
submit = true;
Auth.logout();
$location.path('/');
});
})('votre compte');
};
You should split value with comma and do for loop.
Change "addInterest" function like this:
$scope.addInterest = function () {
if ($scope.interestLimit) return;
var element = $document[0].getElementById('tagInsert'),
value = element.value.split(',');
if (value.length) {
element.value = '';
for (var i = 0; i < value.length; i++) {
if ($scope.interestLimit) break;
if ($scope.user.interests.indexOf(value[i]) === -1) {
$scope.user.interests.push(value[i]);
$scope.interestLimit = $scope.user.interests.length === 10;
}
}
}
};
As far as I understand , you want to split text into string array by comma
Try this code please
<input id='tags' type="text" />
<input type="button" value="Click" onclick="seperateText()" />
<script>
function seperateText(){
var text= document.getElementById("tags").value;
var tags = text.split(',');
console.log(text);
console.log(tags);
}
</script>

Directive's code fires before I got data

This is continuation of this question Get other columns from select ng-options
I have the problems with my directive. First problem is that with the very first initial load of the form I can see correctly department and category, but item shows 'Select Item' instead of the item. The second problem is when I navigate to another row in the list, the initial values are not shown (e.g. everything is showing 'Select Department', 'Select Category', 'Select Item' instead of the values. I confirmed that in that situation I didn't retrieve the row's data yet. So, I need to run directive's code only after I got my data.
How can I resolve my problems?
Here is the whole code for the directive:
(function () {
'use strict';
var app = angular.module('sysMgrApp');
app.directive('smDci', ['departmentService', 'categoryService', 'itemService', smDci]);
function smDci(departmentService, categoryService, itemService) {
var directive = {
restrict: 'E',
scope: {
selectedDepartmentId: '=?departmentid',
selectedCategoryId: '=?categoryid',
selectedItemId: '=itemid',
selectedDci: '=?dci'
},
controller: ['$scope', 'departmentService', 'categoryService', 'itemService',
function ($scope, departmentService, categoryService, itemService) {
$scope.selectedDepartmentId = $scope.selectedDepartmentId || 0;
$scope.selectedCategoryId = $scope.selectedCategoryId || 0;
$scope.selectedItemId = $scope.selectedItemId || 0;
$scope.selectedDci = $scope.selectedDci || '';
var init = function () {
$scope.metaData = {};
window.console && console.log('Selected departmentId = ' + $scope.selectedDepartmentId +
' Selected categoryId = ' + $scope.selectedCategoryId + ' Selected ItemId = ' + $scope.selectedItemId);
departmentService.getAllDepartments().then(function (data) {
$scope.metaData.departments = data.departments;
//window.console && console.log('Got all departments...')
});
if ($scope.selectedDepartmentId == 0 && $scope.selectedCategoryId == 0 && $scope.selectedItemId != 0) {
itemService.getItemById($scope.selectedItemId).then(function (data) {
var item = data.item;
if (item != null) {
$scope.selectedItem = item;
$scope.selectedDepartmentId = item.departmeId;
$scope.selectedCategoryId = item.categoryId;
window.console && console.log('Initial selections are about to fire...')
getInitialSelections();
}
});
}
else {
getInitialSelections();
}
};
var getInitialSelections = function()
{
if ($scope.selectedDepartmentId != 0) {
$scope.departmentChanged($scope.selectedDepartmentId);
}
if ($scope.selectedCategoryId != 0) {
$scope.categoryChanged($scope.selectedCategoryId);
}
}
$scope.departmentChanged = function (departmentId) {
if (!departmentId) {
$scope.selectedCategoryId = '';
$scope.selectedItemId = '';
$scop.selectedItem = {};
$scope.selectedDci = '';
}
else
{
categoryService.getCategoriesByDepartmentId(departmentId).then(function (data) {
$scope.metaData.categories = data.categories;
//window.console && console.dir($scope.selectedItem);
});
}
};
$scope.categoryChanged = function (categoryId) {
if (!categoryId) {
$scope.selectedItemId = '';
$scope.selectedItem = null;
$scope.selectedDci = '';
}
else
{
itemService.getItemsByCategoryId(categoryId).then(function (data) {
$scope.metaData.items = data.items;
});
}
};
$scope.itemChanged = function(item)
{
$scope.selectedItemId = item.itemId;
$scope.selectedDci = item.department + item.category + item.item;
}
init();
}],
templateUrl: 'app/templates/smDci'
};
return directive;
}
})();
and its HTML:
<div class="row">
<label class="control-label col-md-2" title="#Labels.dci">#Labels.dci:</label>
<div class="col-md-3">
<select class="form-control" ng-model="selectedDepartmentId" name="department" id="department"
ng-options="d.departmeId as d.descrip for d in metaData.departments"
data-no:dirty-check
ng-change="departmentChanged(selectedDepartmentId)">
<option value="">#String.Format(Labels.selectX, Labels.department)</option>
</select>
</div>
<div class="col-md-3">
<select class="col-md-3 form-control" ng-model="selectedCategoryId" id="category" name="category"
ng-disabled="!selectedDepartmentId"
data-no:dirty-check
ng-change="categoryChanged(selectedCategoryId)"
ng-options="c.categoryId as c.descrip for c in metaData.categories | filter: {departmeId:selectedDepartmentId}">
<option value="">#String.Format(Labels.selectX, Labels.category)</option>
</select>
</div>
<div class="col-md-3">
<select class="col-md-3 form-control" ng-model="selectedItem" id="item" name="item"
ng-disabled="!selectedCategoryId"
ng-change="itemChanged(selectedItem)"
ng-options="c as c.descrip for c in metaData.items | filter: {departmeId:selectedDepartmentId, categoryId:selectedCategoryId}">
<option value="">#String.Format(Labels.selectX, Labels.item)</option>
</select>
<div class="field-validation-error">
<span ng-show="item.$error.required">#String.Format(Messages.isRequired, Labels.item)</span>
</div>
</div>
</div>
<div class="clearfix"></div>
And this is how I use it in the form:
<data-sm:dci itemid="currentCardAct.itemId" dci="currentCardAct.dci"></data-sm:dci>
Using the logging to console I can see that card data retrieved after I need, e.g. in the console I see
Selected departmentId = 0 Selected categoryId = 0 Selected ItemId = 0
CardActController.js:221 Current Card Activity data retrieved..
smDci.js:28 Selected departmentId = 0 Selected categoryId = 0 Selected ItemId = 0
CardActController.js:221 Current Card Activity data retrieved..
I guess I can add watches in the directive's code, but is it the only option?
I solved the problem by adding a watch. I'm now trying to solve the problem with the initial selection of the item and apparently it's a known problem as referenced here http://odetocode.com/blogs/scott/archive/2013/06/19/using-ngoptions-in-angularjs.aspx about initial selection.

Categories

Resources