I'm working on a pair of Angular functions that should change a value from false to true when the user clicks a button. The app tracks a user's favorite books; when a user creates a favorite, the default values for 'tracking' and 'finished' are set to false. When the user goes to update them to true using an ng-click, the new 'true' values are not patched to the database, and are logged in the console as still false. Any thoughts on what's missing from my functions?
$scope.trackFavorite = function(favorite) {
var favoriteParams = {
id: favorite.id,
tracking: favorite.tracking,
finished: favorite.finished
};
favorite.tracking = !favorite.tracking;
$http.patch("/api/v1/favorites/"+favorite.id+".json", favoriteParams).success(function(response) {
console.log("READING NOW");
console.log(response);
});
};
$scope.markFinished = function(favorite) {
var favoriteParams2 = {
id: favorite.id,
finished: favorite.finished,
};
favorite.finished = !favorite.finished;
console.log(favorite);
$http.patch("/api/v1/favorites/"+favorite.id+".json", favoriteParams2).success(function(response){
console.log("IS IT FINISHED");
console.log(response);
});
};
Here's the ng-click snippets from the view, just in case:
<div>
<button ng-class="{tracking: favorite.tracking}" ng-click="trackFavorite(favorite)">Reading Now</button>
</div>
<div>
<button ng-class="{finished: favorite.finished}" ng-click="markFinished(favorite)">Finished</button>
</div>
Thanks a lot!
There could be a chance that you miss some http configuration. As it has been noticed here: patch request using angularjs.
It would also be a good idea to implement the error function in your controller and for example update the form according to the response, that you get back.
$scope.trackFavorite = function(favorite) {
var favoriteParams = {
id: favorite.id,
tracking: favorite.tracking,
finished: favorite.finished
};
$http.patch("/api/v1/favorites/"+favorite.id+".json", favoriteParams)
.then(
function(response) {
console.log("READING NOW");
console.log(response);
//update the UI according to the response
favorite.tracking = !favorite.tracking;
},function(error){
//clean up when an error occurs
});
};
Related
in my below code using react js i want to make when i click on confirmation alert ok then its show display message success in web page.in my below i when i click on button its confirmation alert is show and when i click on ok then message is not display in web page.
How can we do that is there any help. Its very thankful.
Anyone plz help me out this.
Please check here in my code what i am try to achive
check
The code sandbox you shared was 'logging' the message rather than displaying on the screen. I have updated the code to update the state according to the option user selected.
handleAgree = () => {
this.setState({ agreedState: "I agree!" });
this.handleClose();
};
handleDisagree = () => {
this.setState({ agreedState: "I do not agree!" });
this.handleClose();
};
And finally we can display the message:
{/* Showing message according to the selected option */}
<h1>{this.state.agreedState}</h1>
Here is the updated code sandbox.
I don't really get what you want to do.
You got the code working to display the question prompt.
If you would like to get rid of that only record, you could simply add a ref to your class Component, like this:
constructor(props) {
super(props);
this.myRef = React.createRef(null);
}
Then add the function to handle your deletion logic, e.g: make a POST request to delete that specific item.
handleRemoveItem = (e) => {
const res = window.confirm("Delete the item?");
/**
* Probably a POST request to delete
* the record with the key 'e'.
* Or handle mĂșltiples refs.
*/
if (res)
this.myRef.current.remove();
}
Add ref to button, and you've already done the rest:
<button
className="btn btn-danger"
ref={this.myRef}
onClick={this.handleRemoveItem}
>
If you'd like to display an error or success message, add props to your component, so it's reusable across multiple use cases. But, in order to let you visualize this behaviour, this could be useful:
{(this.state.error || this.state.success) && (
<span className="message">
{this.state.error
? this.state.errorMessage
: this.state.successMessage}
</span>
)}
Add the state to the constructor:
this.state = {
error: false,
success: false,
errorMessage: 'Your error message!',
successMessage: 'Your success messsage'
};
Finally, the logic to your handler:
handleRemoveItem = (e) => {
const res = window.confirm("Delete the item?");
/**
* Probably a POST request to delete
* the record with the key 'e'.
* Or handle mĂșltiples refs.
*/
if (res) {
this.myRef.current.remove();
this.setState({ success: true });
setTimeout(() => this.setState({ success: false }), 3000);
} else {
this.setState({ error: true });
setTimeout(() => this.setState({ error: false }), 3000);
}
}
Code
You can use const res = window.confirm("Delete the item?"); to check click OK or Cancel from alert. After that, you can show your message success as you want when the user clicks OK.
https://codesandbox.io/s/eager-haslett-y63ld?file=/src/index.js
There is a situation that I have to get extra data after my first ajax (in mounted function) in vuejs, I have put the second ajax in if condition and inside success function of the first ajax!
It is working and I see data in Vue Devtools in chrome, but data is not rendered in view.
Pseudo Code:
var vm = new Vue({
el: '#messages',
data: {
participants: [],
active_conversation: '',
messages: []
},
methods: {
getParticipants: function () {
return this.$http.post('message/get-participants').then(
function (response) {
vm.participants = response.data.participants;
// if there is a conversation_id param in url
if (getUrlParameterByName('conversation_id')) {
// Second Ajax Is Called Here inside First Ajax
return vm.getConversationMessages (getUrlParameterByName('conversation_id')); // this ajax call is getting data but not showing in view
}
}
},
getConversationMessages : function(conv_id){
// Second Ajax Call to get Conversation messages
// and showing them , works onClick
return this.$http.post('message/get-messages/' + conv_id).then(
function (response) {
if (response.data.status == 'success') {
console.log(response.data.messages)
vm.messages = response.data.messages;
vm.$forceUpdate();
}
},
mounted: function () {
this.getParticipants()
}
})
The Second Ajax Call to get a specific conversation messages is responding to onclick event and showing messages, but when this function is used inside the First Ajax success response (getParticipants()), its getting data correctly nd I can see in DevTools VueJs Extension that messages are set but view does not show messages, I have tried vm.$set() but no chance.
Update:
The second Ajax is working with no errors and messages data property get filled (I checked Vue DevTools), The only problem is that view does not show the messages!! but when I do it manually by clicking on a conversation, second ajax is executed again and I can see messages!, I also tried vm.$forceUpdate() after second ajax with no chance.
Update2 html part(the bug is here!!)
<a vbind:id="conv.id" v-on:click="getMessages(conv.id)" onclick="$('#user-messages').addClass('active')">
the DOM is updated with messages with when you do the ajax request with only getConversationMessages and not placing
getConversationMessages in the success callback of the ajax request of getParticipants is the fact that an error is encountered at this line
this.participants = response.data.participants;
you are using a normal function in the success callback of the ajax request that's the reason this does not point to the vue instance
adnd this.participants gives you an undefined error. So use vm insteaad to point to the vue instance as you did in the rest of the program
vm.participants = response.data.participants;
Edit
var vm = new Vue({
el: '#messages',
data: {
participants: [],
active_conversation: '',
messages: []
},
methods: {
getParticipants: function () {
return this.$http.post('message/get-participants');
},
getConversationMessages : function(conv_id){
return this.$http.post('message/get-messages/' + conv_id);
}
},
mounted: function () {
this.getParticipants().then(function (response){
vm.participants = response.data.participants;
if (getUrlParameterByName('conversation_id')) {
return vm.getConversationMessages (getUrlParameterByName('conversation_id')); // this ajax call is getting data but not showing in view
}
}).then(function(response){
if (response.data.status == 'success') {
console.log(response.data.messages)
vm.messages = response.data.messages;
});
}
})
Call second http request after first is completed using http callback or you can use Promise too.
return this.$http.post(function(response){
// first call
}).then(function(response){
// Second call
})
new Vue({
el: '#messages',
data: {
participants: [],
active_conversation: '',
messages: []
},
methods: {
async getParticipants (id) {
var response = await this.$http.post('message/get-participants')
this.participants = response.data.participants
if (id) this.getConversationMessages(id)
},
async getConversationMessages (id) {
var response = this.$http.post('message/get-messages/' + id)
if (response.data.status === 'success') {
console.log(response.data.messages)
this.messages = response.data.messages;
}
}
},
created () {
this.getParticipants(getUrlParameterByName('conversation_id'))
}
})
The problem for me was in html, I added a custom onclick event to the div element previously and this event was conflicting with Vuejs events.
I have come to post this question after 2 days of torture not being able to understand how I can actually publish the historic messages stored on my pubnub storage account. To try and understand it at its most basic I have made a chat app and used the history function as described in the SDK but still every time I refresh the page the messages are lost. I have tried the backfill and the restore attributes in subscribe with no luck. All I want to do is click refresh on chrome and see the messages still there.
<div><input id=input placeholder=you-chat-here /></div>
Chat Output
<div id=box></div>
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.4.0.min.js"></script>
<script>(function(){
var pubnub = new PubNub({ publishKey : 'demo', subscribeKey : 'demo' });
function $(id) { return document.getElementById(id); }
var box = $('box'), input = $('input'), channel = 'chat';
pubnub.addListener({
message: function(obj) {
box.innerHTML = (''+obj.message).replace( /[<>]/g, '' ) + '<br>' + box.innerHTML
}});
pubnub.history({
channel: 'chat',
reverse: true, // Setting to true will traverse the time line in reverse starting with the oldest message first.
count: 100, // how many items to fetch
callback : function(msgs) {
pubnub.each( msgs[0], chat );
}
},
function (status, response) {
// handle status, response
console.log("messages successfully retreived")
});
pubnub.subscribe({channels:[channel],
restore: true,
backfill: true,
ssl: true});
input.addEventListener('keyup', function(e) {
if ((e.keyCode || e.charCode) === 13) {
pubnub.publish({channel : channel, message : input.value,x : (input.value='')});
}
});
})();
</script>
</body>
EDIT: updated link that was broken. New version of history function is called fetchMessages.
I think your history code is not correct. No need for the callback as your code response will be in the function argument. This example is from the JavaScript SDK docs.
// deprecated function
pubnub.history(
{
channel: 'chat',
},
function (status, response) {
var msgs = response.messages;
if (msgs != undefined && msgs.length > 0) {
// if msgs were retrieved, do something useful
console.log(msgs);
}
}
);
// latest function (response output format has changed)
pubnub.fetchMessages(
{
channels: ['chat']
},
(status, response) => {
console.log(msgs);
}
);
I have a simple web app based on this project ( https://github.com/arthurkao/angular-drywall ), running with NodeJS and AngularJS as the front-end.
I'm trying to set up a simple page that displays a list of all connected users on a map (using Google Maps, Geolocation and PubNub).
Here's how I'm actually doing it:
angular.module('base').controller('TravelCtrl',
function($rootScope, $scope, NgMap, security, $geolocation, PubNub){
$rootScope.extusers = []; //remote users
$scope.initTravel = function() { //declare the init function
PubNub.init({
subscribe_key: $rootScope.security.keys.psk,
publish_key: $rootScope.security.keys.ppk,
uuid: $rootScope.security.currentUser.username,
ssl: true
});
PubNub.ngSubscribe({
channel: "travel",
state: {
position: {},
}
});
console.log("Loaded Travel");
$geolocation.getCurrentPosition({
timeout: 60000
}).then(function(position) { //when location is retreived
$scope.position = position;
PubNub.ngSubscribe({
channel: "travel",
state: {
position: {
lat: Math.floor($scope.position.coords.latitude*1000)/1000, //decrease accuracy
long: Math.floor($scope.position.coords.longitude*1000)/1000,
},
}
});
$rootScope.$on(PubNub.ngPrsEv("travel"), function(event, payload) {
$scope.$apply(function() {
$scope.extusers = PubNub.ngPresenceData("travel");
});
});
PubNub.ngHereNow({ channel: "travel" });
$scope.showInfo = function(evt, marker) { //show user window on map
$scope.extuser = marker;
$scope.showInfoWindow('infoWindow');
};
});
};
if ($rootScope.hasLoaded()) { //if username and keys are already loaded, then init module
$scope.initTravel();
} else { //else, wait for username and keys to be loaded
$rootScope.$on('info-loaded', function(event, args) {
$scope.initTravel();
});
}
}
);
Although it works, it seems like it's very buggy and only loads sometimes. Occasionally, I get this:
Result screenshot
I really don't know what I'm doing wrong, as I simply followed the tutorials on PubNub's AngularJS SDK.
I think this has to do with how I'm initialising the application.
angular.module('app').run(['$location', '$rootScope', 'security', function($location, $rootScope, security) {
// Get the current user when the application starts
// (in case they are still logged in from a previous session)
$rootScope.hasLoaded = function() {
return (security.keys && security.info && security.currentUser); //check if everything is loaded correctly
};
$rootScope.checkLoading = function() {
if ($rootScope.hasLoaded()) {
$rootScope.$broadcast('info-loaded'); //broadcast event to "TravelCtrl" in order to init the module
}
};
security.requestKeys().then($rootScope.checkLoading); //request secret keys
security.requestSiteInfo().then($rootScope.checkLoading); //then templating info (site title, copyright, etc.)
security.requestCurrentUser().then($rootScope.checkLoading); //and finally, current user (name, id, etc.)
$rootScope.security = security;
// add a listener to $routeChangeSuccess
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
$rootScope.title = current.$$route && current.$$route.title? current.$$route.title: 'Default title';
});
}]);
1- Request secret keys, site info and current user with JSON API.
2- Wait until everything's loaded then init the application with the appropriate keys (PubNub, Google Maps)
--
My question is:
How do you instantiate an AngularJS app after retrieving useful information via a RESTful API?
I'm pretty new to AngularJS, and I wouldn't be surprised if my approach is totally ridiculous, but I really need to get some advice on this.
Thanks in advance for your help,
Ulysse
You don't have to wait that the AJAX Query ended to initate the angular APPs.
you can use the $http promise ( details her )
In the controller :
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
// data is now accessible in the html
$scope.data = response ;
// you can call a function to add markers on your maps with the received data
addMarkerOnMap(response);
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
You can also add a watch on some variable to wait modification on them :
// you should have $scope.yourVarName declared.
$scope.$watch('yourVarName', function(newValue, oldValue) {
console.log(newValue);
});
Or watch a list/object
$scope.$watchCollection('[var1,var2]', function () {
},true);
I've been trying to make a request to a NodeJS API. For the client, I am using the Mithril framework. I used their first example to make the request and obtain data:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://localhost:3000/store/all"});
}
};
var Component = {
controller: function() {
var stores = Model.getAll();
alert(stores); // The alert box shows exactly this: function (){return arguments.length&&(a=arguments[0]),a}
alert(stores()); // Alert box: undefined
},
view: function(controller) {
...
}
};
After running this I noticed through Chrome Developer Tools that the API is responding correctly with the following:
[{"name":"Mike"},{"name":"Zeza"}]
I can't find a way to obtain this data into the controller. They mentioned that using this method, the var may hold undefined until the request is completed, so I followed the next example by adding:
var stores = m.prop([]);
Before the model and changing the request to:
return m.request({method: "GET", url: "http://localhost:3000/store/all"}).then(stores);
I might be doing something wrong because I get the same result.
The objective is to get the data from the response and send it to the view to iterate.
Explanation:
m.request is a function, m.request.then() too, that is why "store" value is:
"function (){return arguments.length&&(a=arguments[0]),a}"
"stores()" is undefined, because you do an async ajax request, so you cannot get the result immediately, need to wait a bit. If you try to run "stores()" after some delay, your data will be there. That is why you basically need promises("then" feature). Function that is passed as a parameter of "then(param)" is executed when response is ready.
Working sample:
You can start playing with this sample, and implement what you need:
var Model = {
getAll: function() {
return m.request({method: "GET", url: "http://www.w3schools.com/angular/customers.php"});
}
};
var Component = {
controller: function() {
var records = Model.getAll();
return {
records: records
}
},
view: function(ctrl) {
return m("div", [
ctrl.records().records.map(function(record) {
return m("div", record.Name);
})
]);
}
};
m.mount(document.body, Component);
If you have more questions, feel free to ask here.