I am making a web application using AngularJS and Laravel. The application is meant to allow the user to post a note on a board. With the code I have, when submitting the note it gets saved to the database but it does not display on the page.
angulartest.blade.php:
<!doctype html>
<html lang="en" ng-app="app">
<title>Test angular</title>
<link rel="stylesheet" href="css/bootstrap.css">
<body>
<div class="container" ng-controller="NoteController">
<h3>Add note</h3>
<form ng-submit="addNote()">
<input type="text" ng-model="newNote.content">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<ul>
<li ng-repeat="note in notes">
#{{ note.content }}
</li>
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.28/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular-route.min.js"></script>
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
app.js
var app = angular.module('app', ['ngRoute']);
app.factory('Data', function Data($http) {
return {
getNotes: function getNotes() { return $http.get('/notes/all'); },
addNote: function addNote(data) { return $http.post('/notes', data); },
removeNote: function removeNote(id) { return $http.delete('/notes?id='+ id); }
}
});
app.controller('NoteController', function NoteController($scope, Data) {
Data.getNotes().success(parseNotes);
function parseNotes(data) {
$scope.notes = data;
}
$scope.newNote = { content: '', poster: '' };
$scope.addNote = function addNote() {
Data.addNote({
content: $scope.newNote.content,
poster: $scope.newNote.post
})
.success(noteAddSuccess).error(noteAddError);
}
function noteAddSuccess(data) {
$scope.error = null;
$scope.notes.push(data);
console.log($scope.notes);
$scope.newNote = { content: '', poster: '' };
}
function noteAddError(data) {
$scope.error = data;
}
$scope.removeNote = function removeNote(id) {
if (confirm('Do you really want to remove this note?')) {
Data.removeNote(id).success(noteRemoveSuccess);
}
}
function noteRemoveSuccess(data) {
var i = $scope.notes.length;
while (i--) {
if ($scope.notes[i].id == data) {
$scope.notes.splice(i, 1);
}
}
}
});
I believe this is all the relevant code. I'm not sure why it is not displaying note.content
Thank you
Since the data update is not triggered from UI, i.e on user clicks or similar activity the scope might be unaware of the changes. In your code you are updating the data from the service, thus my first suggestion will be is to use $scope.$apply() to propagate the changes on the model to the UI.
function parseNotes(data) {
$scope.notes = data;
if (!$scope.$$phase) {
$scope.$apply();
}
}
This might help. If not then, please post back
I found my error, really simple. I was closing div tag before I was requesting {{note.content}}. It should look like:
<div class="container" ng-controller="NoteController">
<h3>Add note</h3>
<form ng-submit="addNote()">
<input type="text" ng-model="newNote.content">
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<ul>
<li ng-repeat="note in notes">
#{{ note.content }}
</li>
</ul>
</div>
thank you for the replies!
Related
I 'm trying to build a chatbot for my Django application. Based on this tutorial, I have made the following javascript and html. The problem is that after sending each message (pressed send button), the chatbot window get closed. Normally it should only be closed after a discussion is finished. I am not sure what has happened. I tried to use prevent default event method(not sure though if I did it correctly), problem still exists.
class Chatbox {
constructor() {
this.args = {
openButton: document.querySelector('.chatbox__button'),
chatBox: document.querySelector('.chatbox__support'),
sendButton: document.querySelector('.send__button')
}
this.state = false;
this.messages = [];
}
display() {
const {openButton, chatBox, sendButton} = this.args;
openButton.addEventListener('click', () => this.toggleState(chatBox))
sendButton.addEventListener('click', () => this.onSendButton(chatBox))
const node = chatBox.querySelector('input');
node.addEventListener("keyup", ({key}) => {
if (key === "Enter") {
this.onSendButton(chatBox)
}
})
}
toggleState(chatbox) {
this.state = !this.state;
// show or hides the box
if(this.state) {
chatbox.classList.add('chatbox--active')
} else {
chatbox.classList.remove('chatbox--active')
}
}
onSendButton(chatbox) {
var textField = chatbox.querySelector('input');
let text1 = textField.value
if (text1 === "") {
return;
}
let msg1 = { name: "User", message: text1 }
this.messages.push(msg1);
fetch('/chatbot', {
method: 'POST',
body: JSON.stringify({ message: text1 }),
headers: {'X-CSRFToken': Cookies.get('csrftoken')},
mode: 'same-origin' //
})
.then(r => r.json())
.then(r => {
let msg2 = { name: "Sam", message: r.answer };
this.messages.push(msg2);
console.log("msg2")
this.updateChatText(chatbox)
console.log("updated chat text")
textField.value = ''
}).catch((error) => {
console.error('Error:', error);
this.updateChatText(chatbox)
textField.value = ''
});
}
updateChatText(chatbox) {
let html = '';
this.messages.slice().reverse().forEach(function(item, index) {
if (item.name === "Sam")
{
html += '<div class="messages__item messages__item--visitor">' + item.message + '</div>'
}
else
{
html += '<div class="messages__item messages__item--operator">' + item.message + '</div>'
}
});
const chatMessages = chatbox.querySelector('.chatbox__messages');
chatMessages.innerHTML = html + chatMessages.innerHTML;
// chatMessages.innerHTML = html;
}
}
const chatbox = new Chatbox();
chatbox.display();
Here is the html:
{% load static %}
<!DOCTYPE html>
<link rel="stylesheet" type="text/css" href="{% static 'css/bot.css' %}">
<head>
<meta charset="UTF-8">
<title>Chatbot</title>
</head>
<body>
<div class="container">
<div class="chatbox">
<div class="chatbox__support">
<div class="chatbox__header">
<div class="chatbox__image--header">
<img src="https://files.softicons.com/download/social-media-icons/free-social-media-icons-by-uiconstock/png/48x48/Reddit-Icon.png" alt="image">
</div>
<div class="chatbox__content--header">
<h4 class="chatbox__heading--header">Chat support</h4>
<p class="chatbox__description--header">Hi. My name is Sam. How can I help you?</p>
</div>
</div>
<div class="chatbox__messages">
{% for message, response,timestamp in chat_history %}
<!-- Response -->
{% if response %}
<div class="messages__item messages__item--visitor">
{{ response }}
</div>
<!-- Message -->
<div class="messages__item {% if response %}messages__item--operator{% else %}messages__item--{% endif %}">
{{ message }}
</div>
{% endif %}
{% endfor %}
</div>
<div class="chatbox__footer">
<form method="post" action="{% url 'chatbot' %}">
{% csrf_token %}
<!-- Input -->
<input type="text" name="message" class="input" placeholder="Type your message here...">
<button type="submit" class="chatbox__send__footer send__button" >Send</button>
</form>
</div>
</div>
<div class="chatbox__button">
<button><img src="https://raw.githubusercontent.com/patrickloeber/chatbot-deployment/ce309f3aae1ccc3783059876a1b66e4d7d77ca9f/standalone-frontend/images/chatbox-icon.svg" /></button>
</div>
</div>
</div>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/js-cookie#2/src/js.cookie.min.js"></script>
<script type="text/javascript" src="{% static 'js/bot.js' %}"></script>
</body>
</html>
In console, the error message is :
Note:
bot.js:69:21 from this line: console.error('Error:', error);
Error: TypeError: NetworkError when attempting to fetch resource.
onSendButton http://127.0.0.1:8000/static/js/bot.js:69
(Async: promise callback)
onSendButton http://127.0.0.1:8000/static/js/bot.js:68
display http://127.0.0.1:8000/static/js/bot.js:19
(Async: EventListener.handleEvent)
display http://127.0.0.1:8000/static/js/bot.js:19
<anonymous> http://127.0.0.1:8000/static/js/bot.js:99
Any ideas? Thank you!
I'm not sure why you get the error, but I have been able to reproduce the error on my machine, and the fix is simple. Change your button to type button instead of submit:
<button type="button" class="chatbox__send__footer send__button" >Send</button>
When the button type is submit, then it will try to send the form the normal route, but you want your JavaScript to handle it instead. If you had a submit event listener, you would use preventDefault() to prevent the button from causing the form to be submitted the normal, default way.
The way you have it now, the button is both trying to send the form the normal route and the JavaScript is also trying to handle the event, and I think that is what is causing the issue.
You could leave the button as type submit and then use preventDefault() by giving the button an id:
<button id="send__button" type="submit" class="chatbox__send__footer send__button" >Send</button>
And then and adding this to your script, outside of chatbox
document.getElementById('send__button').addEventListener('click', (e) => {
e.preventDefault();
});
I'm new to AngularJS, currently I am trying to create a spa for tracking expenses as a simple project but I have some problems with my code.
I managed to do the most of the function but I got stuck at the update function, I want to be able to update the data without creating another button, instead using the same submit button which is used to add new data
Here is the html and js code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Expenses Tracker</title>
<link rel="stylesheet" href="bootstrap.min.css">
<link href="style.css" rel="stylesheet">
</head>
<body>
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<span class="navbar-brand"><img src="logo.png" class="brand" height="40" />
Simple Expenses App Tracker</span>
</div>
</div>
</nav>
<div class="main" ng-app="myList" ng-controller="myListController">
<img src="logo.png" class="logo">
<form ng-submit="newItem()" class="form">
<input required type="number" placeholder="Amount" ng-model="amount">
<input required type="text" placeholder="Description" ng-model="description">
<input type="submit" value="Submit" class="btn btn-success">
</form>
<ul>
<li ng-repeat="item in items">
<span class="pull-left"> {{item.amount}} den.</span> {{item.description}}
<span class="buttons">
<input type="button" ng-click="editItem($index)" value="Edit" class="btn btn-primary" >
<input type="button" ng-click="deleteItem($index)" value="Delete" class="btn btn-danger">
</span>
</li>
<br>
<li><span class="total">{{totalPrice()}} den.</span> <span class="expense"> Total Expenses</span></li>
</ul>
</div>
<script src="bootstrap.min.js"></script>
<script src="angular.min.js"></script>
<script src="angular-route.min.js"></script>
<script src="app.js"></script>
</body>
</html>
var myApp = angular.module("myList", []);
myApp.controller("myListController", function($scope) {
$scope.items = [];
$scope.newItem = function() {
$scope.items.push({description:$scope.description, amount: $scope.amount});
$scope.description = '';
$scope.amount = 0
};
$scope.deleteItem = function(index) {
$scope.items.splice(index, 1);
}
$scope.totalPrice = function() {
var total = 0;
for(count=0; count<$scope.items.length;count++){
total += $scope.items[count].amount;
}
return total;
};
$scope.editItem = function(index) {
$scope.amount = $scope.items[index].amount;
$scope.description = $scope.items[index].description;
};
});
You could have two scope variables to keep track if in edit mode and to keep track of the index that is being edited, and in the newItem() can have an if else statement based on edit mode or not
For example you could do something like
var myApp = angular.module("myList", []);
myApp.controller("myListController", function($scope) {
$scope.items = [];
$scope.isEdit = false; // initialize
$scope.editingIndex = null; //initialize
$scope.newItem = function() {
if(!$scope.isEdit){ //if not in edit mode -> add new
$scope.items.push({description:$scope.description, amount: $scope.amount});
}
else{ //in edit mode -> edit the object
$scope.items[$scope.editingIndex] = { //replace with new values
description:$scope.description, amount: $scope.amount
}
$scope.isEdit = false; //setting back to false
$scope.editingIndex = null;
}
$scope.description = '';
$scope.amount = 0
};
$scope.deleteItem = function(index) {
$scope.items.splice(index, 1);
}
$scope.totalPrice = function() {
var total = 0;
for(count=0; count<$scope.items.length;count++){
total += $scope.items[count].amount;
}
return total;
};
$scope.editItem = function(index) {
$scope.isEdit = true; //setting edit mode true
$scope.editingIndex = index; //setting the index to edit
$scope.amount = $scope.items[index].amount;
$scope.description = $scope.items[index].description;
};
});
demo
I'm new at angularjs and i'm having some serious problems lol...
I've something like this that is working so i don't know whats the problem with this code.. can you help me pls?
Here is it: Basicly the scope.create does not work.. it doesn't even enter in the function..
<!DOCTYPE html>
<html>`enter code here`
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-resource/1.6.5/angular-resource.min.js"></script>
<script>
var app = angular.module('myAppDevice', ['ngResource']);
app.controller('deviceCtrl', ['$scope', '$resource', function($scope,$resource) {
$scope.create = function(a){
console.log("ola");
Device = $resource(
"http://localhost:8080/userapi/postdevice/:userId/:deviceType",
{},
{save: {method:'POST',isArray:false, params: {userId: '#userId',deviceType:'#deviceType'}}}
);
$scope.Message = Device.save({externalId: $scope.deviceForm.userId, deviceType:a});
$scope.deviceForm.userId = "";
};
}]);
function func(){
console.log("ole");
}
app.controller('deviceCtrl', function($scope) {
$scope.myVar = false;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar;
};
});
</script>
</head>
<body ng-app="myAppDevice">
<div ng-controller="deviceCtrl">
<form name="deviceForm">
<div class="form-group">
<img id="device" alt="sensor"
src="http://www.solucoesindustriais.com.br/images/produtos/imagens_10048/p_sensor-de-movimento-para-porta-12.jpg"
width="300" height="150" ng-click="toggle()" />
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<div class="form-group">
<p ng-show="myVar">
userId: <input ng-model="deviceForm.userId" type=text>
</p>
</div>
<div class="btn-wrapper">
<div class="row-gutter-5">
<div class="col-md-4 col-xs-6 col-sm-6">
<button class="btn btn_blue" type="button"
data-ng-click="create(lamp)" id="Create">Create</button>
</div>
</div>
</div>
</form>
</div>
</body>
</html>
Thanks
[EDIT] Thanks guys!! it was solved by removing the controller as you said.. i was starting to be desperate !!
you are duplicating your controller by calling twice "deviceCtrl". Keep it once and try. As the code compiles and execute the latest deviceCtrl will get called and hence the $scope.create() not getting called.
Just remove Second deviceCtrl
app.controller('deviceCtrl', function($scope) {
$scope.myVar = false;
$scope.toggle = function() {
$scope.myVar = !$scope.myVar;
};
});
Here is an working example.
exploring Angular, I built a simple to-do list.
My issue is that when I use the checkbox to delete an item, say the very last one, the item is deleted but the checkbox above it becomes "checked." I just want to be able to delete the item via the checkbox and all the other checkboxes will remain unchecked. I can't figure the bug here. Dimly, I was thinking I needed to reset the "checked" variable, but that wasn't working.
angular.module('ToDo', [])
.controller('ToDoController', function ($scope, ToDoService) {
$scope.items = ToDoService.items;
$scope.checked = false;
$scope.add = function() {
ToDoService.add($scope.todo);
};
$scope.deleteItem = function() {
ToDoService.deleteItem();
};
$scope.remove = function(idx) {
this.items.splice(idx, 1);
console.log("test inside remove");
return this.items;
};
})
.factory('ToDoService', function () {
return {
items: [],
add: function(todo) {
this.items.push({todo: todo, time: new Date()});
},
deleteItem: function(idx) {
this.items.splice(idx, 1);
console.log("test inside deleteItem");
}
};
});
<html ng-app='ToDo'>
<head>
<title>My Angular To-Do App</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src='app.js'></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<link rel="stylesheet" href="app.css">
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">My Angular To-Do App</a>
</div>
</div>
</nav>
<div class="container todos" ng-controller='ToDoController'>
<div class="starter-template">
<h1>My To-Do's</h1>
<div class="alert alert-info" role="alert" ng-show="!items.length">
No to-do items have been added yet.
</div>
<ul>
<li ng-repeat='item in items'>{{item.todo}} - {{item.time}} <a class="btn" ng-click="remove()">Delete</a>
<input type="checkbox" ng-model="checked" ng-change="deleteItem(checked)" >
</li>
</ul>
<form class="form-inline">
<input type='text' ng-model='todo' class="form-control" />
<button ng-click='add()' class="btn btn-default">Add</button>
</form>
</div>
</div>
</body>
</html>
You have complicated your app, using factory is unnecessary here. Another thing - your ng-repeat function didn't set id's of added todos - you were deleting always the first element every time you clicked on delete or on checkbox.
ng-repeat='(id, item) in items'
Lastly - I've added a new feature. With every submit of the todo, the todo input gets cleared.
$scope.todo = null;
Codepen
There are multiple bugs in your application. In your situation, you are calling ToDoService.deleteItem without any parameters when your checkbox change boolean state. So, basically you are doing a this.items.splice(undefined, 1); which removes the first element (indeed what happens in your codepen).
You should change the signature of your deleteItem methods in your service and controller to take the name of the todo. Then, you only have to search it and remove it from the list.
.factory('ToDoService', function() {
return {
....
deleteItem: function(itemStr) {
delete this.items[this.items.findIndexOf(function(item) {
return item ==== itemStr;
})];
},
}
})
then in your template you should call remove with the current todo
ng-change="remove(item.todo)"
Using Kind User answer is even simpler, because you have the direct index of your component,
.factory('ToDoService', function() {
return {
....
deleteItem: function(idx) {
delete this.items[idx];
},
}
})
I am trying to store templates in different html files and load them.
What I am trying to achieve is, when the dropdown is changed, I need to load the particular html file. But it is not even hitting the controller of the file i am loading. What am i doing wrong
Index.html
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="angular.min.js"></script>
<script src="Menu.js"></script>
<div ng-app="MenuApp">
<div ng-controller="MainMenu">
<div ng-include src="getView()"></div>
<select ng-model="Template" ng-change="ChangeTemplate()">
<option value="ListItems">ListItems</option>
<option value="BorderedItems">BorderedItems</option>
</select>
</div>
</div>
ListItems.html (sample template)
<div ng-app="Menu">
<div ng-controller="LoadMenu">
<ol ng-repeat="items in MenuItems">
<li>{{item}}</li>
</ol>
</div>
</div>
Menu.js
(function () {
angular
.module('MenuApp', [])
.controller('MainMenu', MainMenuControllerFunction)
.factory('LoadMenu',['$http',LoadingMenuItemsService]);
function MainMenuControllerFunction($scope, $http, $templateCache) {
$scope.Text = "Hello";
$scope.MenuItems = getMenuItems();
function getMenuItems() {
$http.get("https://gist.githubusercontent.com/vigneshvdm/dc8632bde4e010336356/raw/4fe500385f3249b8bc717d5022c50abb0e07ba75/news").then(function (response) {
$scope.MenuItems=response.data.array;
});
};
$scope.ChangeTemplate = function () {
var template = $templateCache.get('../Html/'+$scope.Template+'.html');
};
$scope.getView = function () {
return "ListItems.html";
};
};
function LoadingMenuItemsService() {
var MenuItems;
$http.get("https://gist.githubusercontent.com/vigneshvdm/dc8632bde4e010336356/raw/4fe500385f3249b8bc717d5022c50abb0e07ba75/news").then(function (response) {
MenuItems=response.data.array;
});
return MenuItems;
};
function ConsumeMenu() {
//$scope.MenuItems = MenuApp.LoadMenu;
alert("");
};
angular.module('Menu', ['MenuApp'])
.controller('LoadMenu', ConsumeMenu);
})();
Do not use functions in templates when you can avoid this.
<select ng-model="template">
<option value="test.html">first</option>
<option value="test2.html">second</option>
</select>
<div ng-include="template"></div>
http://plnkr.co/edit/osB9UiSzvF4IoqkizcOP?p=preview
I think you should use angularjs directives in this case. By using them you could store templates in different html files.