I have a page that culminates in three buttons: a checkout button, a change-qty button, and a cancel button:
<button name="checkout" onclick="location.href='/checkout/'" >checkout </button>
<button name="change" onclick="location.href='/change-qty/'" >change qty</button>
<button name="cancel" onclick="location.href='/cancel-order/'">cancel </button>
I'm doing these redirects in this fashion, instead of using a form, because I want each button to redirect to a different Django view. The code above works fine, but isn't RESTful: "checkout" and "cancel-order" change the system's state, and so I'd like these to be POSTs.
I could achieve this by having the "checkout" and "cancel" views auto-post special-purpose forms to two new views that take POSTs. But that's so much screwing around and complexity-adding. I could also add some jQuery to the page, and have each of those buttons trigger a POST on a hidden form pointed toward the appropriate views, and achieve the same thing. But that, too, is an awful lot of extra code for something that seems pretty simple.
Really, if there was something like a 'method="post"' on a button, that would be perfect. But there isn't. Is there some elegant pattern for achieving what I want? Or am I doing something very stupid and I just don't know it?
Use jquery-ujs, and add "data-" attributes to your links:
change qty
etc. the unobtrusive JavaScript will inject the correct code into your link/button/whatever.
Related
I have an Ember.js component called table-viewer. It has a toolbar which is a div with buttons. I have another ember component called report-viewer. It contains a variety of things including a table-viewer.
I want to have report-viewer add some buttons to the toolbar. What I have works but breaks the Ember connection with the element so I can't change the button text after moving it. Is there a better way to do this?
I have a lot more components than I just said, so defining the complete toolbar in table-viewer and setting flags for what to show would be annoying to manage.
Below is what I currently have in table-viewer so that any component can add additional buttons to the toolbar:
Ember.$('#toolbar').append(Ember.$('#additionalToolbar').html());
Ember.$('#additionalToolbar').remove();
I figured it out! The following works without breaking Ember connections:
Ember.$('#additionalToolbar > button').appendTo(Ember.$('#toolbar'));
It's hard to say what the best approach is without seeing the relevant code. That said, my first suggestion would be a simple yield:
report-viewer/template.hbs
{{#table-viewer}}
<button>
Some button from the report viewer...
</button>
{{/table-viewer}}
table-viewer/template.hbs
<nav>
<button>
Button one
</button>
<button>
Button two
</button>
{{yield}}
</nav>
<table>
...
</table>
If you need more that one yield, you can achieve multiple named yields with this approach.
I'd also suggest splitting the toolbar out into its own component if you haven't already. It feels wrong to put a toolbar button as the block contents of the table-viewer component as I've done above.
Quick note:
I don't believe this is a duplicate of Ember.js: Prevent destroying of views. Other related questions that I've found are out-of-date.
In case this becomes out-of-date later, I am using Ember 1.7.0 with Handlebars 1.3.0.
Context for the question:
As the title states, I am wondering how to transition between views without destroying them. Using queryParams does not solve my issue.
I am creating a calculator with the following nested views:
>>Calculator View
>>Report View (hasMany relationship to Calculator)
--School Partial (I am using queryParams here)
I am able to navigate between the Report views just fine without destroying my School partial, since I am using queryParams and using a displaySchoolPartial boolean to show/hide the partial. Example below:
Report template (stripped to only show the essential part):
<script type="text/x-handlebars" data-template-name="calculator/report">
...
{{#link-to "calculator.report" (query-parameters displaySchoolPartial="true")}}
{{render "_school"}}
</script>
School template (also stripped down):
<script type="text/x-handlebars" data-template-name="_school">
{{#with controllers.calculatorReport}}
<div {{bind-attr class=":schoolPartialWrapper displaySchoolPartial::hide-element"}}>
...
</div>
{{/with}}
</script>
This works as expected. Navigating between different Report views and School partials, as stated before, does not destroy the view.
The problem:
My problem comes when navigating to the Calculator view, the Report view is destroyed, which then destroys my School view. I do not want to also use queryParams to replace my Report views.
The reason I need to make sure the views aren't destroyed is because I have a select box with 3,000 schools in my School partial. It takes too long to re-render this. It would be a much better UX to simply show/hide the Report views.
Don't fight with Ember. You will lose.
Views are instantiated and rendered when needed and torn down when done.
Why do you have a 3000-element dropdown, anyway?
If you really, really want to do this, what I would suggest is putting a {{render}} on your application page, and hide it. The view will be created and rendered when the app comes up and persist as long as the app is alive. Then, in the didInsertElement of your view, do a cloneNode of that hidden element and insert it into the view's DOM somewhere. You may have to muck around getting event handlers wired up correctly.
My suggestion is not using "render" but using "partial", so you only need to drop in the template that you want. Have a control variable that set show/hide via css class. And control that variable using you controllers.
Using "partial" will allow you to have school template independent from report, thereby removing report will not affect school.
Just make sure you define the outlet and partial correctly.
Hope it helps!
I have a simple question which I'm hoping someone will nail in not time.
I'm just running through some Acceptance tests with Codeception and I'm attempting to click a submit button of type image:
<div id="payment">
<input name="submit" type="image" value="" alt="Review your order" src="/images/buttons/pay-securely.png">
</div>
Simply using $I->click() results in a failing test:
$I->click('#payment > input[name=submit]');
Any ideas?
I too have run into trouble with unambiguously specifying what I want to be clicked. Here are two workarounds I have found:
Use a CSS class, or better, an ID, as a selector:
$I->click(['id'=>'myButtonID']);
Use JavaScript / JQuery to trigger the click:
$I->executeJS("$('input[name=submit]').click();");
I prefer the former, because it is easier to do, but I use the latter for cases e.g. where I don't have much control over the code being tested.
I've been in touch with Codeception directly with no reply on the matter. With no way of testing this (and the obvious design flaw in using an image submit button - I mean, are we in the 90s or what?!) I've now changed the input to a proper submit button and CSS that bad boy!
Thought I'd answer my own question and leave it here in the (hopefully unlikely) event that another poor soul has inherited shoddy work.
I wonder if Django native support changes in DOM. I don't know if it is correct name for it now so I guess I explain it instead. For example if I make an e-shop site with django. I want when I click on a product it should add to the basket, which is in html maybe looks something like this. So for each product I add a new <li></li> is added dynamically. Can I do that with django. Or do I have to use Javascript for it?
<div id="basket">
<ul>
<li>
// some product
</li>
</ul>
</div>
It depends.
1) You may want to make you app very dynamic, so another element apears in your basket without page reload. This will be done by combining ajax requests (your server needs to know what you have in basket) with DOM manipulation (purely JavaScript);
2) You can use more classical approach. Adding element to basket is just a POST request. Django handles the request (stores in session or somewhere else current basket) and generates new HTML for you.
Imho, the first approach is a way faster and it looks better for the end-user. The downside is that you may loose track of some valuable information which automatically updates when user reloads entire page (like for example the price of an item). But this should not be a problem if we're talking about store. After all how often product data changes?
Django does not natively generate javascript for you. The usual way is to import your javascript into your pages in your templates.
This might be a very dumb question but I can't find an answer anywhere. I was wondering how do you handle events in Django. I've read the tutorial in their webpage and I cant find a sign of explanation or I'm missing it.
I work in ASP.NET webforms and the way to do that, as you probably know, is putting the event name in the ASP.NET control and calling a particular procedure. I know Django is a very different framework because it's MVC, but I have taken a quick view to a ROR tutorial and I think I've seen they use something similar to ASP.NET webforms, if I've understood correctly, something like embedding ruby code in the html interface and declaring an action there, which I suppose calls the respective function, something like this
<%= ..., action:'action1', ...%> ,which calls a function 'def action1:' in the controller, similar (only in that sense) to asp.net, but webforms doesnt render a view with the name of the function among other things.
So the question is simply that, how do you use events in Django. I hope I was at least a bit clear because it's difficult for me to ask these questions in english
I'm a former ASP.NET developer who switched almost entirely to Django, so I know exactly what you're asking about.
Probably the simplest way I can explain it is this: What you're thinking of as an 'event' would be a URL AND View in Django. Abstract down what you were doing in ASP.NET and it'll make sense -- You had a control, which was just an element on a page. That was mapped to an event, which was really nothing more than a function. So the model of what you're doing looks like this:
object > method
In Django, it's similar, but there's an extra step. ASP.NET automatically connected the object to the method. In Django, you'll need to do that yourself. You do so by creating a URL for that object (urls.py), and then assigning that URL to a view (views.py) which is really nothing more than a method. In Django the same model looks like this:
object > url > method
In many ways they're achieving the same end effect -- something happens and it's handled by a method on the server. Django is simply a bit more open and lets you configure how it happens (and requires that you understand that and handle it yourself).
This concept of control (TextBox, Button, etc.) and page events, in the way you describe, is not carried over to most other frameworks. This was all part of Microsoft's attempt to make the web development experience very similar to that of developing Windows applications -- for better or for worse.
For instance, in a WebForms application:
button.Click += Button_Click;
private void Button_Click(object sender, EventArgs e)
{
// handle action here
}
Would roughly correspond to something like (client-side, in a template):
<form action="/myaction" method="POST">
<input type="submit" value="Click me" />
</form>
Server side view:
def myaction(request):
if request.method == "POST":
# handle action here
pass
In other words, what you want to do in Django and indeed in other MVC frameworks is have unique "actions", or methods, on your controller classes (or view functions in Django). These actions generally respond to HTTP GET and POST requests.
If you want client-side events on your controls, you'll want to look at using a JavaScript framework such as jQuery.
You do this in the view, dependent on the values of the request.POST dictionary.
For example, say you have two buttons on the HTML form, one with name="submit" and one with name="add". Then, in your view, you can do:
if 'add' in request.POST:
# do add action
elif 'submit' in request.POST:
# do submit action
This is exactly how the admin app manages the difference between the "Save", "Save and continue", and "Save and add another" buttons.