I'm trying to use ActionLink to call another controller action and I'm getting an error..resource not found - http-status-code-404

It's putting my parameter into the url and not into my action controller method it looks like. How do I pass a value to my action "SendStaffLeave"? Is the parameter the routeValue?
if (item.BATCH_ID != null)
{
<td>#Html.ActionLink(
linkText:"Email Leave Summary",
actionName: "SendStaffLeave",
controllerName: "Emailer",
routeValues: new {
batch_id = item.BATCH_ID
},
htmlAttributes: new { #class = "btn btn-primary btn-sm", onclick = #"return confirm('Are you sure?')?showModal('Processing','Please wait while your request is processed...'):false;" })</td>
}

Related

Access react's function with parameters from external JavaScript

Is it possible to add onclick event inside the messages' parameter of UIKIT.notification?
Something like this:
notif__undoDelete = (param) => {
setTimeout(function(param) {
UIkit.notification(
`<div class="uk-flex uk-flex-middle uk-margin-medium-right">
<span>Exercise Deleted.</span><a onclick="{here}" class="uk-button uk-button-primary uk-button-small uk-margin-auto-left">Undo</a>
</div>`,
{ timeout: 6000, pos: "bottom-left" }
)
}, 800, param)
}
I use this answer to solve my problem
Call react component's function from external JavaScript function
I added in componentDidMount method first:
componentDidMount () {
var me = this
window.undoDelete = () => {
var external_me = this
let param = JSON.parse(external_me.event.target.getAttribute("data-param"))
me.undoDelete(param)
}
}
I have an undoDelete() method somewhere and when I call my UIkit.notification it's gonna be something like this and my react's undoDelete() method will be called. I added data-param as well to pass parameters.
UIkit.notification(
`<div className="uk-flex uk-flex-middle uk-margin-medium-right">
<span>Item Deleted.</span>
<a onclick="window.undoDeleteExternal()" data-param='`+ JSON.stringify(param) +`' className="uk-button uk-button-primary uk-button-small uk-margin-auto-left">Undo</a>
</div>`,
{ timeout: 6000, pos: 'bottom-left' }
)

Vue.js: Manipulate Array and post form with new data

In my Vue.js application I want to post form data to my Node.js/MongoDB Backend.
This is my source code: https://github.com/markusdanek/t2w-vue/blob/master/src/components/backend/JobEdit.vue
JSON for my job entry: http://t2w-api.herokuapp.com/jobs/591c09a55ba85d0400e5eb61
Relevant code for my question:
HTML:
<div class="row">
<input type='text'
:name="'qual'+index"
v-model="qualifications[index]">
<button #click.prevent="removeQualifiaction(index)">X</button>
</div>
Methods:
onChange(value, $event){
if (!this.job.xmlOnline)
this.job.xmlOnline = []
const index = this.job.xmlOnline.findIndex(v => v == value)
const checked = $event.target.checked
if (checked && index < 0)
this.job.xmlOnline.push(value)
if (!checked && index >= 0)
this.job.xmlOnline.splice(index, 1)
}
removeQualifiaction() {
this.qualifications.splice(this.qualifications.index, 1);
}
Sending the form data with submit button on form end:
editJob() {
let job = Object.assign({}, this.job);
job.qualifications = this.qualifications;
job.responsibility = this.responsibility;
this.$http.post('https://t2w-api.herokuapp.com/jobs/' + this.$route.params.id, job).then(response => {
console.log(response);
}, response => {
console.log(response);
});
}
My problems now:
When I edit a "Job", I have a list of "qualification items", that are input fields in my form.
Clicking the "delete" button results that the first input gets deleted, not the one I am clicking. Done with #thanksd answer.
How do I add a button and method to add a new input field and to append it to my job.qualifications?
In my JobAdd.vue implemented, to add a new entry to job.qualifications, like this:
<a #click.prevent="addQualification">+</a>
addQualification() {
this.qualification.push({ text: '' });
}
addJob() {
let job = Object.assign({}, this.job);
job.qualifications = this.qualification.map(q => q.text);
this.$http.post('https://t2w-api.herokuapp.com/jobs/', job).then(response => {....
Full source for my JobAdd.vue: https://github.com/markusdanek/t2w-vue/blob/master/src/components/backend/JobAdd.vue
this.qualification.push({ text: '' }); doesnt work obviously not in my JobEdit.vue when there are already strings in my job.qualifications.
Change your removeQualifiaction method to use the index being passed in:
removeQualifiaction(index) {
this.qualifications.splice(index, 1);
}

Why is my state being updated here?

I'm pretty new to React, but liking it so far. I'm building a large application, which is going well, except I've run into an issue. I'm building a list of responses to questions, and they can be deleted, but I also want to have a "Cancel" button so all unsaved changes can be reverted. What is confusing me is the cancel button reverts to the initial state for the name value, but not the responses. If I add in some console logging to the response deletion script, I would expect to see log lines 1 & 2 match, with 3 being different. However, I'm seeing that 1 is the original, but 2 & 3 match. Why is state being updated before I call setState, and why does updating state seem to update the my initial props?
EDIT: I added a jsFiddle
getInitialState: function() {
return {
name: this.props.question.name,
responses: this.props.question.responses,
};
},
handleCancelButtonClick: function(e) {
this.replaceState(this.getInitialState());
},
handleNameChange: function(e) {
this.setState({name: e.target.value});
},
handleResponseDeletion: function(e) {
var resp = this.state.responses;
var from = Number(e.target.value);
console.log(JSON.stringify(this.state.responses));
resp.splice(from, 1);
console.log(JSON.stringify(this.state.responses));
this.setState({responses: resp});
console.log(JSON.stringify(this.state.responses));
},
render: function() {
var key = "mp" + this.props.question.name;
var resp = [];
if (this.state.responses) {
this.state.responses.forEach(function(response, i) {
var rkey = "r_" + this.props.question.name + "_" + i;
resp.push(<ModalResponse response={response} key={rkey} value={i} deleteResponse={this.handleResponseDeletion} />);
}.bind(this));
}
return (
<layer id={this.props.question.name} style={questionModal} key={key}>
<h2>Edit {this.state.name}</h2>
<button onClick={this.handleCancelButtonClick}>Cancel</button>
<div class='form-group'>
<label for='client_name' style={formLabel}>Question Name:</label><br />
<input type='text' style={formControl} id='question_name' name='question_name' value={this.state.name} onChange={this.handleNameChange} required />
</div>
<div class='form-group'>
<label style={formLabel}>Responses:</label><br />
<ul style={responseList} type="response_list" value={this.props.qname}>
{resp}
</ul>
</div>
</layer>
);
}
});
The problem is that splice modifies original array. It means the one that belongs to the original question. So when you call getInitialState from within handleCancelButtonClick you get modified array.
To avoid this you need to somehow clone original data inside getInitialState. For example
getInitialState: function() {
//copy array and responses
const copy = resp => ({...resp})
return {
name: this.props.question.name,
responses: this.props.question.responses.map(copy)
};
}
Here's what I did to fix the issue:
handleResponseDeletion: function(e) {
var resp = []
var from = Number(e.target.value);
this.state.responses.forEach(function(res, i) {
if (i != from) {
resp.push(res);
}
});
this.setState({responses: resp});
},

Angular expressions in formlyConfig.setType

The biggest question here is: Why would an expression like this class='{{prodStatusTextColor}}' not be updated in the view if the value of the variable scope.prodStatusText is indeed getting the new values?
Explanation:
I have an application that has a model that is loaded after search results and can be altered using a history function to load another dataset. The history function is contained in another grandparent scope. I have been able to confirm that the obj values that I am using for the dom changes do indeed update and hold the correct values when they should, (in the console) on the first load of the data and on the history change.
I am using formly-form and have a template set that contains 2-way bound variables to change styles and icons based on another fields values.
Templates follow:
formlyConfig.setType({
name: 'prodStatus',
template: "<label class='control-label'>Production Status</label><br><span class='{{prodStatusTextColor}}'><i class='{{prodStatusStatusIcon}}'></i> <span class='{{prodStatusTextColor}}'>{{model[options.key]}}</span> <!--i class='{{prodStatusInfoIcon}}'></i--></span>"
});
//term date
formlyConfig.setType({
name: 'termDate',
template: "<div data-ng-show='inclTermDate'><label class='control-label text-danger'>Termination Date</label><i class=fa fa-lg fa-calendar-times-o></i> <span class='text-danger'> {{model[options.key] | date:'yyyy-MM-dd'}} </span></div>"
});
I tried to use a service and define a default value for the variables as part of an existing model that was working. I could see the value changes but they were not being added to the html. I think they are just not being instantiated by the time the page renders?
Rendered HTML:
<div formly-field="" ng-repeat="field in fields " ng-if="!field.hide"
class="formly-field ng-scope ng-isolate-scope col-sm-6 col-lg-3 col-md-4
formly-field-prodStatus" options="field" model="field.model || model" fields="fields" form="theFormlyForm" form-id="formly_10" form-
state="options.formState" index="$index"><label class="control-label ng-scope">Production Status</label><br class="ng-scope"><span class=""><i class="">
</i> <span class="">Inactive</span> <!--i
class='{{prodStatusInfoIcon}}'></i--></span></div>
<label class="control-label ng-scope">Production Status</label><br class="ng-scope">
<span class=""><i class=""></i> <span class="">Inactive</span> <!--i class='{{prodStatusInfoIcon}}'></i--></span></div>
partial formly obj:
{
className: 'col-sm-6 col-lg-3 col-md-4',
key: 'AGENT_LNAME',
type: 'input',
templateOptions: {
type: 'text',
label: 'Last Name',
placeholder: 'Agent Last Name'
},
expressionProperties: {
'templateOptions.tabindex': '4'
},
watcher: {
expression: function(field, scope) {
return field.formControl && field.formControl.$viewValue;
},
listener: function(field, newValue, oldValue, scope, stopWatching) {
agentPersInfoModel.chng = {
prodStatusTextColor: "text-success",
prodStatusStatusIcon: "fa fa-lg fa-check-circle-o fa-lg",
prodStatusInfoIcon: "fa fa-lg fa-info-circle",
isActiveStatus : false,
inclTermDate : false
};
scope.prodStatusTextColor = agentPersInfoModel.chng.prodStatusTextColor;
scope.prodStatusStatusIcon = agentPersInfoModel.chng.prodStatusStatusIcon;
scope.prodStatusInfoIcon = agentPersInfoModel.chng.prodStatusInfoIcon;
scope.inclTermDate = agentPersInfoModel.chng.inclTermDate;
scope.isActiveStatus = agentPersInfoModel.chng.isActiveStatus;
if(newValue) {
console.log('Function Expression: ' + newValue);
console.log('Field: ');
console.log(field);
console.log('oldValue: ' + oldValue);
console.log(oldValue);
console.log('Scope: ');
console.log(scope);
console.log("agentPersInfoModel.chng");
console.log(agentPersInfoModel.chng);
console.log("agentModel prod status");
console.log(agentModel.singleAgent.PRODUCTION_STATUS);
if(agentModel.singleAgent.PRODUCTION_STATUS === 'Active' && agentModel.singleAgent.TERMINATION_DATE === "00010101") {
agentPersInfoModel.chng.isActiveStatus = true;
agentPersInfoModel.chng.prodStatusTextColor = "text-success";
agentPersInfoModel.chng.prodStatusStatusIcon = "fa fa-lg fa-check-circle-o fa-lg";
agentPersInfoModel.chng.prodStatusInfoIcon = "fa fa-lg fa-info-circle";
agentPersInfoModel.chng.inclTermDate = false;
console.log("============= in the listner (history) =====================");
console.log("we are active");
console.log("agentPersInfoModel.chng.prodStatusInfoIcon");
console.log(agentPersInfoModel.chng.prodStatusInfoIcon);
console.log("agentPersInfoModel.chng.prodStatusStatusIcon");
console.log(agentPersInfoModel.chng.prodStatusStatusIcon);
console.log("agentPersInfoModel.chng.prodStatusTextColor");
console.log(agentPersInfoModel.chng.prodStatusTextColor);
console.log("agentPersInfoModel.chng.inclTermDate");
console.log(agentPersInfoModel.chng.inclTermDate);
console.log("==================================");
} else if(agentModel.singleAgent.PRODUCTION_STATUS === 'Inactive') {
agentPersInfoModel.chng.prodStatusTextColor = "text-warning";
agentPersInfoModel.chng.prodStatusStatusIcon = "fa fa-ban fa-lg";
agentPersInfoModel.chng.prodStatusInfoIcon = " fa fa-lg fa-alert ";
agentPersInfoModel.chng.inclTermDate = false;
console.log("============= in the listner (history) =====================");
console.log("we are inactive");
console.log("agentPersInfoModel.chng.prodStatusInfoIcon");
console.log(agentPersInfoModel.chng.prodStatusInfoIcon);
console.log("agentPersInfoModel.chng.prodStatusStatusIcon");
console.log(agentPersInfoModel.chng.prodStatusStatusIcon);
console.log("agentPersInfoModel.chng.prodStatusTextColor");
console.log(agentPersInfoModel.chng.prodStatusTextColor);
console.log("agentPersInfoModel.chng.inclTermDate");
console.log(agentPersInfoModel.chng.inclTermDate);
console.log("==================================");
} else if(agentModel.singleAgent.TERMINATION_DATE !== "00010101") {
agentPersInfoModel.chng.prodStatusTextColor = "text-danger";
agentPersInfoModel.chng.prodStatusStatusIcon = "fa fa-times fa-lg";
agentPersInfoModel.chng.prodStatusInfoIcon = " fa fa-lg fa-alert ";
agentPersInfoModel.chng.prodStatusCalIcon = " fa fa-lg fa-calendar-times-o ";
agentPersInfoModel.chng.inclTermDate = true;
console.log("============= in the listner (history) =====================");
console.log("we are term'd");
console.log("agentPersInfoModel.chng.prodStatusInfoIcon");
console.log(agentPersInfoModel.chng.prodStatusInfoIcon);
console.log("agentPersInfoModel.chng.prodStatusStatusIcon");
console.log(agentPersInfoModel.chng.prodStatusStatusIcon);
console.log("agentPersInfoModel.chng.prodStatusTextColor");
console.log(agentPersInfoModel.chng.prodStatusTextColor);
console.log("agentPersInfoModel.chng.inclTermDate");
console.log(agentPersInfoModel.chng.inclTermDate);
console.log("==================================");
} else {
agentPersInfoModel.chng.isActiveStatus = false;
agentPersInfoModel.chng.prodStatusTextColor = "text-warning";
agentPersInfoModel.chng.prodStatusStatusIcon = "fa fa-ban fa-lg";
agentPersInfoModel.chng.prodStatusInfoIcon = " fa fa-lg fa-alert ";
agentPersInfoModel.chng.inclTermDate = false;
console.log("============= in the listner (history)=====================");
console.log("we didnt match");
console.log("agentPersInfoModel.chng.prodStatusInfoIcon");
console.log(agentPersInfoModel.chng.prodStatusInfoIcon);
console.log("agentPersInfoModel.chng.prodStatusStatusIcon");
console.log(agentPersInfoModel.chng.prodStatusStatusIcon);
console.log("agentPersInfoModel.chng.prodStatusTextColor");
console.log(agentPersInfoModel.chng.prodStatusTextColor);
console.log("agentPersInfoModel.chng.inclTermDate");
console.log(agentPersInfoModel.chng.inclTermDate);
console.log("==================================");
}
}
}
},
controller: /*#ngInject*/function($scope, AgentPersInfoModel) {
$scope.switchTermColors = function (status) {
};
}
}
console.log:
agentModel prod status
agentPersonalInfoFormly-service.js:221 Inactive
============= in the listner (history) =====================
agentPersonalInfoFormly-service.js:245 we are inactive
agentPersInfoModel.chng.prodStatusInfoIcon
agentPersonalInfoFormly-service.js:247 fa fa-lg fa-alert
agentPersInfoModel.chng.prodStatusStatusIcon
agentPersonalInfoFormly-service.js:249 fa fa-ban fa-lg
agentPersInfoModel.chng.prodStatusTextColor
agentPersonalInfoFormly-service.js:251 text-warning
agentPersInfoModel.chng.inclTermDate
agentPersonalInfoFormly-service.js:253 false
The history function simply fetches a new agent based on an id and loads that into the existing agentModel, does not actually touch these functions, these are supposed to change if the agentModel changes.
Any discussions or assistance would be greatly appreciated.
All the "code" inside your main div is actually in a new child scope created by the ng-repeat="field in fields " therefore any primitives (like prodStatusTextColor) that you use inside it are shadowed (they "hide" the original variable after they copy their initial value).
You should try using the . dot notation instead, as per angular recommandations (check this doc on scopes): you should encapsulate those variables inside an object and use them by reference.
Something like this:
in the listener you may have:
prodStatus = {
prodStatusTextColor: agentPersInfoModel.chng.prodStatusTextColor,
prodStatusStatusIcon: agentPersInfoModel.chng.prodStatusStatusIcon,
prodStatusInfoIcon: agentPersInfoModel.chng.prodStatusInfoIcon,
inclTermDate: agentPersInfoModel.chng.inclTermDate,
isActiveStatus: agentPersInfoModel.chng.isActiveStatus
};
and in the view markup you can use it like this:
<i class='{{prodStatus.prodStatusInfoIcon}}'></i>
Even simpler, you may want to put the agentPersInfoModel directly in the scope:
scope.agentPersInfoModel = agentPersInfoModel.chng;
and use it in the markup:
<i class='{{agentPersInfoModel.prodStatusInfoIcon}}'></i>
Hope this helps!
Code is not tested but should do the work.

Polymer iron-ajax: How can I send value to an argument of a function

First of all I want to say sorry for not-so-good title for this post. I could not think of anything better!
I am trying with iron-ajax. When I enter a value in my iron-input element and click on a button I get result fine. Now each record in the result has a link which is supposed to drill down more into the item itself.
To get first set of result I have done the following (which works fine):
<iron-ajax id="ajax"
handle-as="json"
on-response="hresponse"
last-response="{{data}}"
debounce-duration="300">
</iron-ajax>
<input is="iron-input" id="txtSearchItemsByName"/>
<button on-click="findItems">Search ยป</button>
<span id="waiting"></span>
<template is="dom-repeat" items="{{data}}">
<div>
<span>
<input id="itemId" value="{{item.id}}"/>
<a on-click="itemDetail( {{item.id}} )" href="javascript:;" title="{{item.plantid}}">{{item.title}}</a>
</span>
</div>
</template>
Following code block fetches all records which match the name entered by user
findPlants: function () {
var thisAjax = this.$.ajax;
var waitingContainer = this.$.waiting;
waitingContainer.innerHTML = "Please wait...";
var strEnc = encodeURIComponent(this.$.txtSearchItemByName.value);
this.$.ajax.url = "//domain.com/api/v0/items/search";
this.$.ajax.params = { "apikey": "xxxxxxxxxxx", "common_name": strEnc };
window.setTimeout(function () {
thisAjax.generateRequest();
waitingContainer.innerHTML = "";
}, 1000);
},
hresponse: function (request) {
data = this.$.ajax.lastResponse;
},
Up to this point everything works fine. Then I went on and created another function which is supposed to take an argument:
itemDetail: function (id) {
var thisAjax = this.$.ajax;
var waitingContainer = this.$.waiting;
waitingContainer.innerHTML = "Please wait...";
this.$.ajax.url = "//domain.com/api/v0/item/search";
this.$.ajax.params = { "apikey": "xxxxxxxxxx", "id": id };
window.setTimeout(function () {
thisAjax.generateRequest();
waitingContainer.innerHTML = "";
}, 1000);
},
And I expect the following line to do my job:
<a on-click="itemDetail( {{item.id}} )" href="javascript:;" title="{{item.plantid}}">{{item.title}}</a>
However, when I am clicking on the link I am getting the following error message and nothing is happening:
[iron-ajax-caller::_createEventHandler]: listener method itemDetail( {{item.id}} ) not defined
I have no idea what to do from here as I am still a newbie at Polymer.
Experts please help!
Thanks in advance,
Subrata
Use on-tap instead of on-click:
<a on-tap="_itemDetail" href="javascript:;" title="{{item.plantid}}">{{item.title}}</a>
Then in your function:
_itemDetail: function(e) {
var thisAjax = this.$.ajax, waitingContainer = this.$.waiting;
thisAjax.url = '//domain.com/api/v0/item/search';
thisAjax.params = { apikey: 'xxxxxx', id: e.model.item.id };
this.async(function() {
thisAjax.generateRequest();
waitingContainer.innerHTML = '';
}, 1000);
}
See documentation here for more info
As to why on-tap, check this out
I believe you made a simple mistake, if I'm not totally wrong. This:
<a on-click="itemDetail( {{item.id}} )" href="javascript:;" title="{{item.plantid}}">{{item.title}}</a>
should look like this:
<a on-click="{{itemDetail(item.id)}}" href="javascript:;" title="{{item.plantid}}">{{item.title}}</a>
I think it should work. Polymer 1.0 doesn't support string concatenation. In your case it can't put these together "itemDetail(" + item.id + ")". And therefore the syntax is as I described above.
<a on-click="itemDetail" data$="{{item.id}}" title="{{item.plantid}}">{{item.title}}</a>
itemDetail : function(e){
console.log(e.target.getAttribute("data"));
}

Resources