how to send data from the function to angular material dialog? - angular-material

I got the data from clicking the row of the table. Now I got the data, then how do I send data to the dialog component and use it?
rowClicked(data) {
console.log("row data");
console.log(data);
const dialogRef = this.dialog.open(DashboardTableDialogComponent, {
scrollStrategy: new NoopScrollStrategy(),
});
dialogRef.afterClosed().subscribe((result) => {
console.log(`Dialog result: ${result}`);
});
}

From your component, where you are creating an instance of Dialog Component, we need to send data to Dialog as below:
const dialogRef = this.dialog.open(DashboardTableDialogComponent, {
scrollStrategy: new NoopScrollStrategy(),
data : data //This is where you can pass data to your dialog component.
});
Inside the DashboardTableDialogComponent, Get the data via Dependency Injection as shown below:
private data:any;
constructor ( #Inject(MAT_DIALOG_DATA) public data: any, ...)
{
this.dataFromParent = data;
}
Hope this should help your problem.

Related

Kendo Upload control remove event has no response

I have a kendo upload control like this:
#(Html.Kendo().Upload()
.Name("attachments")
.Async(a => a
.Save("UploadAsync", "Intel")
.Remove("RemoveAsync", "Intel")
.AutoUpload(true)
)
.Events(e => e
.Success("onSuccessfulUpload")
.Remove("onRemoveFile")
)
.Validation(v => v.AllowedExtensions(exts))
)
In the controller, its Save method is like this:
public ActionResult UploadAsync(IEnumerable<HttpPostedFileBase> attachments)
{
string filename;
// ... do things ...
return Json(new { ImageName = filename }, "text/plain");
}
where the variable filename is assigned a value.
Its Remove method in the controller looks very similar:
public ActionResult RemoveAsync(string[] fileNames)
{
string filename;
// ... do things ...
return Json(new { ImageName = filename }, "text/plain");
}
I verified that both controller methods are called correctly and the variable filename is assigned to in both cases.
The upload works as expected, and the Success event also works as expected. (The alert is simply for testing.)
function onSuccessfulUpload(e) {
alert(e.response.ImageName);
}
The issue comes on removal of a file.
When I get to the Remove event, e does not have a .response. It has e.files and e.sender, but no response.
function onRemoveFile(e) {
alert(e.response); // undefined!
alert(JSON.stringify(e.files)); // works, but does not have what I need
}
How do I access what the RemoveAsync method returns?
It looks like the remove event doesn't provide this kind of data, so I see only a workaround to solve this.
You could try to put the result name to the headers, and you should be able to read the result:
// Controller
Response.AddHeader("ImageName", imageName); // before Json(...)
// View/JS
alert(e.headers['ImageName']);
I haven't tested that and I see a risk that that the remove event doesn't really read the async response, that would explain why the response object is not available.
In that case, you could try to use the following workaround: Don't call any Url on remove (or use some Action without any body, just a plain result) and inside of the event callback, execute RemoveAsync yourself.
// View/JS
function onRemoveFile(e) {
$.post('#Html.Url("RemoveAsync", "Intel")', e.files, function(response) {
alert(response);
});
}
It's not pretty, but it should work and provide the results you need.
After some time poking around, I found the answer.
The key lay in the order of the events. My first assumption was that the Success event was called after successful upload, and the Remove event was called after successful(?) removal. This was wrong.
The actual order of the events is:
JS onUpload > Controller UploadAsync > JS onSuccess
JS onRemoveFile > Controller RemoveAsync > JS onSuccess
My Solution:
I created two parallel arrays in javascript to represent the files uploaded in the client-side e.files, which contains uid's for each file, and the filenames created by the server-side controller method (which renames the files).
var fileUids = [];
var fileSaveNames = [];
I changed the onSuccessfulUpload function to this, when I discovered that there is an e.operation that specifies which operation was the successful one:
function onSuccess(e) {
if (e.operation == "upload") {
var filename = e.response.ImageName;
var uid = e.files[0].uid;
// add to the arrays
fileUids.push(uid);
fileSaveNames.push(filename)
// ...
}
else if (e.operation == "remove") {
var uid = e.files[0].uid;
var saveIdx = fileUids.indexOf(uid);
// remove from the arrays
fileSaveNames.splice(saveIdx, 1);
fileUids.splice(saveIdx, 1);
// ...
}
}
Then I updated the removeFile function, which I now knew was called before the method in the controller.
function removeFile(e) {
var uid = e.files[0].uid;
var idx = fileUids.indexOf(uid);
e.data = { fileToRemove: fileSaveNames[idx] };
}
That last line, where I assign to e.data, was because of this thread on the Telerik forums, which has the following info:
Solution: All that's needed it to define a function for the upload
event and modify the "data" payload.
Add the upload JS function to add a parameter "codeID" in my case.
$("#files").kendoUpload({
[...]
upload: function (e) {
e.data = { codeID: $("#id").val() };
}
});
Now on the controller add the parameter and that's it.
[HttpPost]
public ActionResult Save(IEnumerable<HttpPostedFileBase> files, Guid codeID) { }
(Instead of being in the Upload event, mine is in the Remove event.)
I chose the parameter name fileToRemove, and now the new RemoveAsync method in the controller is as such:
public ActionResult RemoveAsync(string[] fileNames, string fileToRemove)
{
string returnName = "";
if (!string.IsNullOrWhiteSpace(fileToRemove))
{
// ... do things ...
}
return Json(new { ImageName = returnName }, "text/plain");
}

Bind Element to controls SAPUI5

I'm trying to show some data retrieved by Odata Model on a XML View.
In Component.js, I create a model with service Url and it works as usual.
var oDataModel = new sap.ui.model.odata.v2.ODataModel("http://server:port/sap/opu/odata/SAP/ZWYMB_SRV", {
user:"abapleader",
password: "TH123456789a#",
headers: {
"sap-client": 300
},
useBatch:false
});
this.setModel(oDataModel, "oDataModel");
So far, I've managed to get data to master using model.read() function.
Now I need to show the detail view. My code for onInit event is below:
this.router.getRoute("zwm01detail").attachPatternMatched(this._onObjectMatched.bind(this));
},
_onObjectMatched: function(oEvent) {
var that = this;
var MaWorkDoc = oEvent.getParameter("arguments").MaWorkDoc;
this.getModel("oDataModel").metadataLoaded().then(function() {
var sPath = that.getModel("oDataModel").createKey("/WorkDocList", {
MaWorkDoc: MaWorkDoc,
Pernr: "0001"
});
console.log(sPath);
that.getView().bindElement({
path:sPath
});
});
The sPath as I printed out using console.log(sPath) : /WorkDocList(MaWorkDoc='1110000001',Pernr='0001'), which I think, is correct. I also implemented and tested the back-end using this path and basically things are fine. But I don't know why I cannot show data on the view.
Detail.view.xml:
<Text text="{/MaWorkDoc}" maxLines="0"/>
Any suggestions, please?
Because you have given your model a name you will need to use that name in the binding. i.e. <Text text="{oDataModel>/MaWorkDoc}" maxLines="0"/>
So I've been working around with the docs and figure out there is model parameter which helps.
To be more specific, I add declare model in view.bindElement as below:
that.getView().bindElement({
path:sPath,
//** oDataModel = name of the model
model: "oDataModel"
});
If there is any better solution, I'd very glad to know it. Thank you.!
I do not think the detail binding code should be inside the .metadataLoaded handler. Rather it should be directly inside _onObjectMatched.
I mean like this.
_onObjectMatched: function(oEvent) {
var that = this;
var MaWorkDoc = oEvent.getParameter("arguments").MaWorkDoc;
var sPath = that.getModel("oDataModel").createKey("/WorkDocList", {
MaWorkDoc: MaWorkDoc,
Pernr: "0001"
});
console.log(sPath);
that.getView().bindElement({
path:sPath
});
}

ajax request php class function

i have content listed in a div and i have a dropdown with various options to order and filter that content.
I'm using ajax to filter/order that content and is working but i use other php page with the content i want on the div that has the content, like this
function order(str){
$.post("order_products.php",
{
q: str,
},
function(data, status){
document.getElementById("txtHint").innerHTML = data;
});
}
What i wanted was to instead of putting the code (data) to change in another page just for that, i could put that code inside a class php function that i have.
<?php
class products{
function list(){
blablabla
}
That way i would "save space" and organize everything, considering that i have many other things to order/filter but i don't know to to make the ajax request to that function, or if it's possible without having a page in between and then get the response from the function and put it on the div.
You can do this using Laravel by setting up a route to a function that will do the ordering. Please note I've made a lot of assumptions in the following answer as I can't see all your code and have made it quite general, please adjust the code to your project or provide more details of your code if you don't understand the answer fully.
routes.php
Route::post('products/order', [
'as' => 'products.order',
'uses' => 'ProductsController#orderProducts'
]);
Your view (assuming you're using blade)
$txtHint = $('#txtHint'); // grab the reference to txtHint dropdown
$.post( '{{ route("products.order") }}', // hit our route
{
q: str,
},
function(data, status){
$txtHint.empty(); // clear the dropdown
// loop through the data and assign each element to the dropdown
$.each(data, function(value, key) {
$txtHint.append($("<option></option>")
.attr("value", value)
.text(key));
});
});
ProductsController.php
public function orderProducts()
{
$orderBy = \Input::get('q');
return \Products::lists('name', 'id')->orderBy($orderBy);
}
For outside of a framework just change the url to your php file and add in a data attribute for the method you require to be fired from the file.
$.post( 'products.php', // hit our route
{
action: 'order',
q: str,
},
...
Then in products.php you'd do something like this
if(isset($_POST['action']) && !empty($_POST['action'])) {
$action = $_POST['action'];
switch($action) {
case 'order' : order();break;
case 'otherFunction' : otherFunction();break;
}
}
function order()
{
// order logic here
// get $_POST['q']
// do your ordering
// return data as json
}
See here for similar question: using jquery $.ajax to call a PHP function

breezejs how to using as datasource

i'm using breezejs for some time now, and i'm happy about it and it's rich functionality , but the problem with breezejs is that i cant use it as datasource almost for anything.
there is no grid that you could show data and not losing functionality, and you cant use your array of entities as normal array. (so you cant use it as datasource for dropdown ...)
so for showing data in UI i end up converting data to normal array and losing Breeze functionality (like track change) and before save converting them back.
some code like this one for converting to normal array:
if(data.length>0)
{
var names = Object.getOwnPropertyNames(data[0]._backingStore);
var columns: string[] = [];
for (var i = 0; i < names.length; i++)
{
columns.push(names[i]); //Getting columns name
}
var newArray = [];
data.forEach((item, index, array) => {
newArray.push(item._backingStore);
});
}
my question is how do you show your data in UI using breezejs properly?
(i'm using angualr (hottowel))
Assuming you're trying to solve issues like this:
The grid doesn't like the entityType and entityAspect properties on Breeze entities.
This grid doesn't know how to handle Knockout style "properties" that are functions.
Creating a POCO object using the Breeze entity's property values disconnects you from the change tracking goodness.
You could try creating your POCO object using Object.defineProperty, using the Knockout observable as the property's getter and setter functions. Here's a simple example:
Typescript + Knockout:
class PocoBreezeEntity {
constructor(private entity: breeze.Entity) {
entity.entityType.dataProperties.forEach(
dataProperty => {
Object.defineProperty(
this,
dataProperty.name,
{
get: entity[dataProperty.name],
set: entity[dataProperty.name],
enumerable: true,
configurable: true
});
});
}
}
Typescript + Angular:
class PocoBreezeEntity {
constructor(private entity: breeze.Entity) {
entity.entityType.dataProperties.forEach(
dataProperty => {
Object.defineProperty(
this,
dataProperty.name,
{
get: function() { return entity[dataProperty.name]; },
set: function(newValue) { entity[dataProperty.name] = newValue; },
enumerable: true,
configurable: true
});
});
}
}
With this kind of approach you have the benefits of POCO entities without losing the Breeze change tracking.

Change title when opening dialog from knockout binding

I have based my code on this example
http://jsfiddle.net/rniemeyer/WpnTU/
When you select an item I want the title of the dialog to have a observable's value
I managed to to it by creating another custom binding
ko.bindingHandlers.dialogOptions = {
update: function(element, valueAccessor) {
var options = ko.utils.unwrapObservable(valueAccessor());
if (options ) {
$(element).dialog(options);
}
}
}
Added a new observable to viewmodel and set it when the item is selected
this.selectProduct = function(product) {
self.dialogOptions({ title: product.name() });
self.selectedProduct(product);
}
Working example: http://jsfiddle.net/WpnTU/76/
It works but I do not like it, it adds a new observable which is very coupled with the GUI, it would be much nicer if I could use the already exiting selectProduct observable and point out the name property in the GUI something like { title: selectProduct.name }
Here is a sample that moves the .dialog calls into the update function and unwraps the options, so that it will be triggered any time that something changes.
//custom binding to initialize a jQuery UI dialog
ko.bindingHandlers.jqDialog = {
init: function(element) {
ko.utils.domNodeDisposal.addDisposeCallback(element, function() {
$(element).dialog("destroy");
});
},
update: function(element, valueAccessor) {
var options = ko.toJS(valueAccessor());
if (options) {
$(element).dialog(options);
}
}
};
I added a computed observable to your sample just to handle the selectedProduct being null (could be done in-line).
http://jsfiddle.net/rniemeyer/Gt5Hw/

Resources