React keep data attribute - reactjs

I have to do a 'simple' task. It is actually simple if you know the react framework or have any Javascripts knowledge in particular but my Javascript knowledge is pretty terible so I am really stuck now.
What I am trying to achieve is, I have a button 'terminate' in a table (so several rows). When I click the button, I want the console log to throw me the transactionID of that row. But I really cannot get it to work. This is what I have currently:
I have a class with in it several methods, of one is a 5 sec auto refresh function:
var ExceptionalCases = React.createClass({
I created this method:
TerminateCase: function(e) {
e.preventDefault();
this.setState({
}, function() {
var transactionID = this.refs.transid.target.getAttribute("data-transid");
console.log('button clicked' + transactionID);
}.bind(this));
},
And this is the button (located in the render):
<input type="button" name="TerminateCase" value={_('Terminate')} style={{width: '110px'}}
onClick={this.TerminateCase} ref="transid" data-transid={entry.transactionId}/>
This is the error I get:
TypeError: this.refs.transid.target is undefined
I am clueless, I searched alot and tried many different approaches but I am really stuck now. I hope that someone can help me ;-(

Try this:
TerminateCase: function(e) {
e.preventDefault();
var transactionID = e.currentTarget.getAttribute("data-transid");
console.log('button clicked' + transactionID);
}

Related

Controller Stuck at component.get("v.recordId")

I am trying to get case record Id using lightning button but my controller is not moving forward from this line -component.get("v.recordId")
I don't know what is wrong.
Please help:
This my component
<aura:component controller="EmailSendController" implements="flexipage:availableForRecordHome,force:hasRecordId,force:lightningQuickAction" access="global">
<lightning:button label="Send Notification" title="Send Notification" onclick="{!c.sendMail}"/>
This is my controller
({
sendMail: function(component, event, helper) {
console.log("Button Clicked--");
var caseID = component.get("v.recordId");
Console.log("CaseID--"+ component.get("v.recordId") );
var action = component.get("c.sendMailMethod");
action.setParams({
"caseId" : caseID
});
action.setCallback(this, function(response) {
var state = response.getState();
Console.log("Response"+response.getState());
if (state === "SUCCESS") {
//var storeResponse = response.getReturnValue();
}
});
$A.enqueueAction(action);
},
})
JavaScript is case-sensitive. 2nd Console should be lowercase, I suspect it throws an error about undefined object.
You can use your browsers JS console (in Chrome Ctrl+Shift+J) to inspect such errors. It also helps to go to Setup -> Debug Mode and add your user in there. SF will get bit slower but you'll see more human-readable code and errors instead of optimised, minified mess.
If it still throws errors - use console to check what error exactly and edit your question?
P.S. change it in callback handler too

'Dashboard not a constructor' error with Google Charts

I am a naive React Developer and facing some difficulty with getting gooogle chart work with react. I am using Google Charts in a ReactJs component with ControlWrapper as shown below.
componentDidMount: function(){
google.charts.load('current', {'packages':['corechart', 'controls']});
this.drawCharts();
},
componentDidUpdate: function(){
google.charts.load('current', {'packages':['corechart', 'controls']});
this.drawCharts();
},
drawCharts: function(){
var cmpt = this;
//Removed detailed code from here due to copyright issues
//adding controls----------------
let dashboard = new google.visualization.Dashboard( document.getElementById(cmpt.props.widgetId) );
let controlId = '${this.props.widgetId}_control';
var controlWrapper = new google.visualization.ControlWrapper({
'controlType' : 'NumberRangeFilter',
'containerId' : controlId,
'options' : {
'filterColumnLabel' : xDataSysName
}
});
var barChart = new google.visualization.ChartWrapper({
'chartType': 'BarChart',
'containerId': this.props.widgetId,
'options': options
});
dashboard.bind(controlWrapper, barChart);
dashboard.draw(data);
if(linkColumn){
let selectionEventHandler = function() {
window.location = data.getValue(barChart.getSelection()[0]['row'], 1 );
};
google.visualization.events.addListener(barChart, 'select', selectionEventHandler);
}
}
},
This is not the whole piece of code but should be enough for the issue I'm facing.
First time I load the page, I get the error in the console saying
google.visualization.Dashboard is not a constructor
I reload the page hitting SHIFT+F5, the error goes away and components load just fine except ones that are dependent on controlWrapper throwing the error as follows
google.visualization.controlWrapper is not a constructor
which never goes away even after reloading the page. I referred to this discussion and tried their solution but I am still getting these error in the manner mentioned above. Please help me figure out how to fix it. Also, I am not able to comprehend why dashboard error goes away on a reload.
need to wait until google charts has fully loaded before trying to use any constructors,
this is done by providing a callback function.
try changing the load statement as follows...
componentDidMount: function(){
google.charts.load('current', {packages:['corechart', 'controls'], callback: this.drawCharts});
},
componentDidUpdate: function(){
google.charts.load('current', {packages:['corechart', 'controls'], callback: this.drawCharts});
},

View changing on fullcalendar doesn't work

I'm facing this nightmare since many days and I still cannot figure what I'm missing to make the changeView event work.
What am I doing? I'm programmatically trying to make the calendar's view changed. How? Searching for fullcalendar by his id within the controller and setting the new view.
Lots of guides/threads tell many ways but the more comprehensible I got was the following:
That's my HTML code (it's the whole HTML page):
<div class="container">
<div id="eventsCalendar" ui-calendar="main.uiConfig.calendar" class="span8 calendar" ng-model="main.eventSources">
</div>
</div>
This's how to get the calendar, setting the new view within the controller:
angular.element('#eventsCalendar').fullCalendar('changeView', 'agendaView');
It looks fine, no errors and angular got the calendar (yay!!!). Amazing! No "calendar-related-dependencies" injected, a very simple and short way... That's awesome! Set a function with that line of code but nothing happened and the calendar still be in the month view (holy damn... back to the drawing board...)
Some threads for the ui-calendar (maybe something similar to fullcalendar?) tells to inject uiCalendarConfig as controller's dependency, declaring the calendar="myCalendar" attribute in HTML declaration and calling uiCalendarConfig.calendars.myCalendar... the result was: uiCalendarConfig is empty... I'm confused.
Does anyone ever get the changeView work properly? How could I do that? I'm sure I'm missing something stupid... I can feel it!
Any help will be appreciated.
<div calendar="eventsCalendar" ui-calendar="main.uiConfig.calendar" class="span8 calendar" ng-model="main.eventSources">
To change the calendar view, use this function
$scope.changeView = function(view) {
uiCalendarConfig.calendars["eventsCalendar"].fullCalendar('changeView',view);
};
call the function as below
$scope.changeView('month'); //or
$scope.changeView('agendaDay'); //or
$scope.changeView('agendaWeek'); //or
Unfortunately, there does not seem to be an onload callback. However, this is what I came up with for my app
// watcher for on load
var calendarOnLoad = null;
var calendarOnLoadCallbacks = [];
$scope.changeView = function(view) {
if(uiCalendarConfig.calendars.eventsCalendar) {
// already initiated or beat the race condition, great!
uiCalendarConfig.calendars.eventsCalendar.fullCalendar('changeView',view);
}
else {
// calendar is undefined. watch for onload
if(!calendarOnLoad) {
calendarOnLoad = $scope.$watch(function () {
// prevent type error which breaks the app
try {
return uiCalendarConfig.calendars.eventsCalendar;
} catch (err) {
return null;
}
}, function (calendar) {
// uiCalendarConfig.calendars.eventsCalendar is now initiated
if(calendar) {
calendarOnLoad(); // clear watcher since calendar exists
// call all the callbacks queued
calendarOnLoadCallbacks.forEach(function (fn) {
fn(calendar);
});
}
});
}
// run this calendarOnLoadCallbacks queue once calendar is initiated
calendarOnLoadCallbacks.push(function(calendar) {
calendar.fullCalendar('changeView',view);
});
}
}
$scope.changeView('agendaWeek');
$scope.changeView('month');
$scope.changeView('agendaDay');
I hope this helps.

Saving data with updated values in Backbone.js

I am working on MVC application with Backbone.js.
Assuming, I have a View of User details:-
var userDetailsView = Backbone.View.extend({
model: userModel,
el: "#userDteails",
template: Handlebars.templtas.userDetails
initialize: function () {
this.model = new userModel();
this.model.fetch({
success: function (data) {
this.render();
}
});
},
render: function () {
$(this.el).html(this.template());
},
events: {
"", "saveUserDetails" //event for save
},
saveUserDetails: function () {
//How do I get the update value of FirstName??
}
});
Now, in similar line I have a handlebar template which deals with edit details of User Model.
<div id="userDetails">
<input type="text" value="{{FirstName}}" id="firstName"/>
</div>
Please ignore the code mistakes as its just a dummy code, now if I need to save the user details(say for eg. FirstName). Then how do I get the updated value?
Should it be:-
saveUserDetails: function () {
//How do I get the update value of FirstName??
this.model.set("", $('#Firstname').val());
}
or should I follow converting form data to JSON, and update my this.model i.e create my HTML markup with name attribute:-
<form>
First Name:<input type="text" name="Fname" maxlength="12" size="12"/> <br/>
</form>
and use the function suggested by Tobias Cohen
$.fn.serializeObject = function()
{
var o = {};
var a = this.serializeArray();
$.each(a, function() {
if (o[this.name] !== undefined) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value || '');
} else {
o[this.name] = this.value || '';
}
});
return o;
};
and do :-
$('form').submit(function() {
$('#result').text(JSON.stringify($('form').serializeObject()));
return false;
});
I am not an expert in Backbone, but have seen at-least 10-15 samples and tutorials which teach backbone. Out of those I found the above two way to do it.
Please let me know, what would be best way to proceed.
Both ways are OK! It depends on how complex your HTML <-> Model mapping is. If everything can be done with div/span/input with a name/data-name or whatever floats your boat, then the serializing route is straightforward. But once you grow out of that, you'll probably look at more custom ways, which is technically similar to your first option, with a bit more logic that just getting the .val() from the input field.
I don't really understand both of your example handling tho, but you said to not worry about the details... so :) For the form one, I assume that the .text() is just for debugging purpose? The correct code would probably first preventDefault() on the form submitting and then do a model.save($('form').serializeObject()) to both update the model and save it on the server at the same time. With some success/error call back thrown in for good measure!

How do I simply refresh a view in Backbone?

I'm brand new to backbone and just learning the basics. I am building an image gallery with backbone. I am displaying a large version of an image. The routing is working properly. When a url is passed with an id the appropriate JSON is loaded into the model and the html is injected into the dom. Everything displays as expected.
However, I tried entering a url for the JSON for an image that didn't exist and noticed that the view still rendered but with the previously rendered view's properties (image url) still present. How do I ensure that the view is refreshed - all empty properties? Or is it the model that needs to be refreshed?
Note: I am re-using the view to avoid the overhead of creating and dystroying the view itself.
Here is the view in question:
var ImageView = Backbone.View.extend({
template: Handlebars.compile(
'<div class="galleryImageSingle">'+
'<h2>{{title}}</h2>' +
'<img id="image" src="{{imageUrl}}" class="img-polaroid" />' +
'<div class="fb-share share-btn small"><img src="img/fb-share-btn- small.png"/></div>'+
'</div>' +
'<div class="black-overlay"></div>'
),
initialize: function () {
this.listenTo(this.model, "change", this.render);
//this.model.on('change',this.render,this);
},
fbSharePhoto: function () {
console.log('share to fb ' + this.model.attributes.shareUrl)
},
close: function () {
//this.undelegateEvents();
this.remove();
},
render: function () {
this.$el.html(this.template(this.model.attributes));
this.delegateEvents({
'click .fb-share' : 'fbSharePhoto',
'click .black-overlay' : 'close'
});
return this;
}
})
Here is the router:
var AppRouter = Backbone.Router.extend({
routes: {
"" : "dashboard",
"image/:iId" : "showImage",
},
initialize: function () {
// this.galleriesCollection = new GalleriesCollection(); //A collection of galleries
// this.galleriesCollection.fetch();
this.imageModel = new Image();
this.imageView = new ImageView ({ model: this.imageModel });
},
dashboard: function () {
console.log('#AppRouter show dashboard - hide everything else');
//$('#app').html(this.menuView.render().el);
},
showImage: function (iId) {
console.log('#AppRouter showPhoto() ' + iId);
this.imageModel.set('id', iId);
this.imageModel.fetch();
$('#imageViewer').html(this.imageView.render().el);
}
});
Is is it that the model still has the old info or the view, or both?
For extra credit, how could I detect a failure to fetch and respond to it by not triggering the corresponding view? Or I am I coming at it wrongly?
Thanks in advance for any advice.
////////////////////////////////////////////////////////////////////////////
Looks like I found something that works. I think just the process of framing the question properly helps to answer it. (I'm not allowed to answer the question so I'll post what I found here)
It appears that its the model that needs refreshing in this case. In the app router when I call the showImage function I clear the model and reset its values to default before calling fetch and this did the trick. Ironically the trick here is showing a broken image tag.
showImage: function (iId) {
console.log('#AppRouter showPhoto() ' + iId);
this.imageModel.clear().set(this.imageModel.defaults);
this.imageModel.set('id', iId);
this.imageModel.fetch();
$('#imageViewer').html(this.imageView.render().el);
}
For my own extra credit offer: In the event of an error (if needed fetch() accepts success and error callbacks in the options hash). Still definitely open to hearing about a way of doing this thats baked in to the framework.
You can just update the model like this:
ImageView.model.set(attributes)

Resources