App.PhotoUpload = Ember.TextField.extend
type: "file"
change: (evt) ->
# #get('controller') gives - App.PhotoUpload
#get('controller').send('uploadImage')
In above code,if I debug it and check #get('controller').constructor it returns App.PhotoUpload, which is not right and it doesn't call uploadImage action which is in my route.
When I change Ember.TextField to Ember.View, #get('controller') works as expected and uploadImage action is called. But, as Im doing auto update to server on image upload, I need to stick with TextField.
I have these questions:
1. What are ways to access another controller from Emberview ?
2. How can I get access to right controller from Ember.TextField ??
The problem here is that the included input fields were recently modified to extend Ember.Component instead of Ember.View. One of the primary differences between a component and a view is that the controller property of a component is itself. Honestly, I'm not totally sure why that change was made. Having said that, it's still possible to access the controller from the context of where the text field was defined using the targetObject property.
Update:
I looked into this a bit more and it turns out that not all input fields were turned into components, only the TextField and TextArea. It appears the primary reason for turning them into components was to expose some helpful action handlers since components provide that capability.
Related
I'm currently facing a problem with Meteor and React, where i know some partly solutions but they don't work and imo none of them is pointing in the true direction.
The situation:
All is about an fitness app: I have a structure that represents exercises for customers, while each exercise can have a defined number of sets (a set is how often a exercise should be done). Each set has some properties (all the user can manipulate within the font-end).
Now i have the following component structure with some map-functions (state properties are in {}):
Training {customers,exercises,datetime,otherinfos}
- Overview {customers,exercises}
exercises.map():
- Exercise {exercise,customers}
customers.map():
- Customer {exercise,customer}
exercise.sets.map()
Set {exercise, customer, set, valuesofset}
From a UI-perspective (react) this all works without problems.
Now the idea is to have a button "Save" within the Training component. When the button is pressed, I want to save the state of all Set-Components in a "sets" collection (if it has other values than the default placeholder ones) and at the same time save the Training-Component in a "trainings" collection. But the training should also include information about what Sets are integrated (so at least the Set._id should be in the Training-Component state at time of Saving.
Here now my ideas so far:
Create refs from Training all the way down to all Sets and then, when pressing "Save" iterate over all refs and call a "Mongo.insert" from all Sets. Here i have the problem that i cannot return the inserted _id. Of course i could call a different function in each Component from Set all the way back to Training, but imo this is an overflow.
Try to manage the state of all sets within the Training state by calling a nested function. As i have onChangeHandler on the Inputs, this would always call a method in Training and check which one of the Sets was changed and then changes it. I have tried it this way, but it led to a very bad performance.
Create a temp-ID for Training, forward it to to the Sets (using the componentWillReceiveProps method) and when in Set, insert the Set in the database with the temp-ID. Then receive all Sets with temp-ID and use it to add the Training in the database. --> imo very complicated and I don't really want to do a database call if it is not necessary.
So currently i don't know how to solve this problem. The reason i try to separate "sets" and "trainings" is given through the fact, that later on i would like to give information about the last Set right next to the new empty Set whenever one is on the database. Any tips are welcome!
EDIT:
As suggested, there is also the possibility to solve the problem with Session. So therefor i have added the following code to Set:
componentDidMount() {
Tracker.autorun(() => {
Session.set(`set_${this.state.id}`, {
...this.state
});
});
}
My idea was then to iterate over all Session-Keys from Training which start with "set_" - unfortunately there is no function to that holds all Keys.
Second idea was to to use an array as value for a Session-pair. However, it's quite a procedure to handle the update of the reactive Set component (copy array from session, check whether an element is available or not, create a new one or update the existing one).
EDIT2:
I think i got a solution with Session:
Object.getOwnPropertyNames(Session.keys)
did the trick to get all SessionKeys! Thank you for your help!
If you do not want to use Redux or pass parent bound callbacks in the child component, you can try Session to store data at app level which can be accessed(set/get) in any component
https://docs.meteor.com/api/session.html
In your case, you may set values of "Set" in Session and access it in Training. You may also need https://guide.meteor.com/react.html#using-withTracker. Using withTracker will help in doing reactive update of the database on change of any Session variable.
I am pretty confused about this issue.
I have template which has two paths as follows:
Router.route('/companyDataManagement',{
path:['/companyDataManagement','/companyDataManagement/:_id'],
name: 'companyDataManagement',
yieldTemplates:{
'companyData':{to:'showCompanyData'},
'companyDetails':{to:'showCompanyDetails'}
}
});
This works perfectly fine. But how do I use pathFor for this template.
Click does not work
Can you confirm if the companyDataManagement in the link is a name being passed from a helper or if you intend this to be the name of the route called? if it is the latter it needs to be encapsulated in single quotation marks like below
Click
If you want to then pass the :_id into the pathFor this comes from the data context which the link is in, if the data context does not supply the id you need to declare an object to pass into the template inside a helper:
Template.yourTemplate.helpers({
myContextHelper: function(){
return {_id:'XXXXXXXXX'}
}
});
{{#with myContextHelper}}
Click
{{/with}}
Which should give you /companyDataManagement/XXXXXXXXX
You can also pass in the query, hash and data variables using for example query="q=1" or query=qstring where qstring is an object from a helper or a field in the myContextHelper object.
Click
Additionally and not strictly to do with the question but is hopefully helpful, it looks from your code like you are just having the :id as an optional route part in your path and that the templates themselves do not require an :_id to be specified, in which case you can just use a ? to make the part optional:
path:'/companyDataManagement/:_id?',
You can also use this for your opening argument for the route to eliminate having to specify the path in the function:
Router.route('/companyDataManagement/:_id?',{
Hope this helps! Let me know if the above doesn't work happy to help troubleshoot if you can post a bit more of the code surrounding it
I am using knockout in my project. I have multiple viewmodel, each viewmodel have its own save function implemented in it. Now whenever user clicks on save button the viewmodel data post to the server, i want to block the save button until the response came back from server.
Currently i am handling this by creating an extra observable property saving in each viewmodel. So when user click over the save button i am setting saving observable to true and in callback i am setting it to false. And i have bind this saving property with the button using knockout disable binding.
But i feel that this approach is not good and it contains the following big drawbacks:
For this i have to add an extra property in each viewmodel.
I have to add multiple line of code like setting it to true and again set it to false.
The approach is not centralize, the code for this approach is scattered.
So i want to know is there any other better way to handle this, a plugin or some standard way ??
Edit
Just to clarify, my question has nothing to do with asp.net postback, the question is how i can handle efficiently the ajax, like block the save button, displaying the response message etc
??
This is generally what makes a viewmodel a viewmodel. In a pattern like MVC, your controller shouldn't really have any idea what your view looks like, what controls it has, or what it's state is, and your model only contains data for the view to model. In an MVVM pattern, as knockout is, your viewModel actually does have knowledge of the current states of controls on the view. This isn't to say your viewmodel should directly update the view, but it usually will contain properties that are bound to states of the view. Things like SaveButtonEnabled or IsSavingData or even things like StatusLabelColor are accepted in a viewmodel.
Perhaps use $.ajaxSetup(). You call this in your document ready function.
$.ajaxSetup({
beforeSend: function(jqXHR)
{
//this will be called before every
//ajax call in your program
//so perhaps, increment an observable viewmodel variable
//representing the number of outstanding requests
//if this variable is > 0 then disable
//your button
},
complete: function(jqXHR)
{
//this will be called after every
//call returns
//decrement your variable here
//if variable is zero, then enable button
}
});
I'd recommend you take a look at http://durandaljs.com/, a framework using Knockout and has some great data patterns, even if you don't use it directly.
I have a big problem with using Knockout JS. In my view model I have a field, called Method, that is actually an other view model.
This view model can be one of three different things (it is mapped to a polymorphic object in the domain model). To solve this I use templates that checks which type of Method that is selected withing the domain model and then shows the template that binds data for that type.
The function that checks the type of method looks like:
this.getTemplate = function (data) {
var method = data.original.get_Method();
if (method instanceof MyProj.MethodA)
return "methodA";
else if (method instanceof MyProj.MethodB)
return "methodB";
else if (method instanceof MyProj.MethodC)
return "methodC";
}
The markup where I bind the template looks like:
<div data-bind="template: {name: getTemplate($data), data: $data.Method}"></div>
This actually works very nice and when I change the type of method via an dropdown in the UI the domain model updates and the right template is shown. However here comes my problem. Each template contains a number of different fields that are specific for each method type. Whenever I change one of the values in the view model displayed by one of the templates the UI flashes and I think that happens because the template get selected again. This is quite irritating and looks extremly bad.
Any ideas on how to solve this problem? Any help would be greatly appreciated!
Thanks in advance
/Björn
Did you use any observable inside the getTemplate function. Updating the value of that observable makes the template rerender and you get your flash effect.
Checkout this link Part : "Note 5: Dynamically choosing which template is used".
I have an application in ASP.MVC. The requirement is that I select a person from a list of people and click 'Info' and it should load the details of the person in that page. I have the Info controller and everything works fine if I go to the Info page from a different controller. In the page I am trying to make it work with JavaScript and it doesn't seem to take me to the desired page but to a different controller.
I have a ToDoList controller and in the .cshtml I have this code on click of the Info link.
function DoInfo#(i.ToString())() {
$("#sessionid").val("#Model.cSessionId[i]");
alert("hey");
$("#PageController").val(66);
$("#formID").submit();
}
I go to the ToDoList controller to do the redirection like this
if (viewModel.PageController == 66)
{
pass = new PassingData();
pass.personid = TSSessionService.ReadPersonId(viewModel.SessionId);
TempData["pass"] = pass;
return RedirectToAction("Index", "Info");
}
It never goes there and instead goes to a different controller. I cannot seem to find how they are linked and why is it not going back to controller where the Info link button is i.e. back to the ToDoList controller.
Let me know if it is not clear and I will try to explain again and I will give any other details.
I guess I'm confused as to why you are doing this as a combination of form and JavaScript. Are there other properties that you need to pass along that you are not posting above? Why do you need to use JavaScript to do this if you are just returning a new view?
You indicate in your post that when a person is selected from a list you need to go to a controller and display a view. This seems fairly straightforward, and I would like to suggest simplifying the problem.
Start with this: change your link to not use a form or JavaScript. Just make it a link. If it is text, you can use #Html.ActionLink() and even pass in the parameters you need.
If you're not displaying text, just use #Url.ActionLink() in your href property of the anchor you're wrapping your element with. Both of these allow you to leverage routing to ensure the correct path is being constructed.
If the controller that you are trying to get to has access to whatever TSSessionService is, then you don't need to pass through the TempData["pass"] you are trying to push through, so it makes it cleaner in that way as well.
If you do need to submit a more complicated value set, I would recommend coming up with a generic .click() event handler in jQuery that can respond to any of the clicks, bound by a common class name. You can use a data-val attribute in your link and read from $(this).attr('data-val') in your handler to store/fetch other important info. This allows you to more easily build up an object to POST to a controller.
Hope this helps some, but if I'm missing a critical point then please update the question above.