#changeorders
Explore tagged Tumblr posts
Video
youtube
How to change order of products on shopify https://youtu.be/L8903L1-ros #changeorder #shopify #shopifystore #ecommerce #earnmoneyonline #howto1minute #shopifyproduct
0 notes
Text
Framing has begun!
Stopped by the site last weekend and got to see the beginning of the framing process!
Here’s the driveway (above) with a bunch of framing material waiting to be nailed into place, and beyond you can see our new bedroom and bathroom addition! The window opening on the left will be the bathroom (small toilet room area), and the two windows on the right are our bedroom.
At the corners you can see our Simpson Stongwalls - structural steel used to stiffen the north façade framing that is mostly window openings. You can also see that only 1 top plate has been added so far. Once they add the second top plate the top of the wall will align with the top of the large header over the center window and everything will be strapped together.
You can see the hold downs bolted through the strongwall base and the sill plate framing. The sill plates (bottom pieces of wood on the concrete slab) are pressure treated wood (looks green) to avoid water and rot issues where the wood framing is most susceptible to water intrusion.
Here you have Brett (and I) critiquing the less than stellar concrete skills of our contractor. Not to mention his sweet tall socks with the shorts (LOL), yes I married him for his keen eye for fashion... ahem I mean construction errors. The concrete edge of our slab bows out toward the driveway and at the center point is about 1/2 inch proud of the sill plate, but it aligns at the corners. Yes we are perfectionists in our work... but even more so when it’s our house! Meanwhile I am also wondering how the hell we are going to be able to plant anything between our addition and the driveway?? Our design left room for an approximately 30″ wide planting strip between the addition and the driveway. BUT the contractor poured the large footings for the strongwall at this corner (that thing he’s standing on) just about level with the top of the driveway! Last time I checked, you can’t grow anything in a concrete footing. And we didn’t construct this addition to allow a raised planter against the wall... I guess I’ll be stuck with potted plants here and I’m not pleased. I also don’t know how they are going to pour the new walkway up to our porch when this blob of footing concrete is about level with where that walk needs to be. The contractor is likely going to have to chip some of this concrete out of there to do it right... ugh!
Here’s the back addition (above) - they had not started framing that area yet when we visited, but they have taken the back wall and part of the roof off. The rest of that roof on the right side needs to be removed to get rid of the dutch-gable and will be re-framed with a standard gable to facilitate our vaulted ceiling in the great room.
Above you can see the recess in the new slab where it meets our existing slab. This recess is for the new sliding door track!
Here’s a sample piece of that track in the recess. Once all the flooring is installed, all you will see will be less than a 1/4-inch tall section of the top silver part of the track, and the base will be buried below. They better set that track more level than they poured that recess... We paid $250 for this recess as a part of change order #2... Looking at how uneven it is, I’m thinking we were overcharged!
We did argue with our contractor about some items in change order #2: he was trying to double charge us for structural items that were in our permit set and the plans showing those items were sent to him prior to his first bid. It was super annoying to argue this with him... lots of #rantsbybrett were endured by all! During our meeting with the contractor I had to shush the ranting husband so that I could talk reasonably with contractor about how he was completely wrong... but you know, in a professional way. Then we had to send a bunch more emails proving our case which was totally BS because the structural items were in the bid set and the permit set! If this change order went to court, 10 times out of 10 we would have been declared right! I even got personally offended that the contractor tried to sick his admin lady on me to try to get me to back down... as if I’m a push over - think again! HA! Their only argument was, “none of our other home owners contest our change orders.” Uhhh... then your other home owners are idiots! We are architects AND it’s our money we’re talking about here so he better bring a better excuse than that if you want us to pay. He finally agreed to revise the change order after I bitched that we are paying them hundreds of thousands of dollars and they are trying to argue about a couple grand, and furthermore, we are spending far too much of our valuable time even arguing about this item that seems pretty clear. Very frustrating.
Above you can see where they demolished the front door wall that had that funky plumbing pipe that was going at a 45-degree angle through the framing of the wall. Our new front door will be in the same location, but we are raising the header over the door all the way up to the underside of the rafters and that will allow us to have an 8′ tall front door! The door will be centered on the front porch with an operable side light on either side. The roof over the porch is getting removed and re-framed for a 10′ tall ceiling above the porch. So that beam with the white paint being supported by a another piece of wood, sitting on another scrap block of wood on the ground is all going away!
It was admittedly a little scary to walk around the house in this condition because structurally some items are not really braced at the moment in their temp condition... we were very cautious not to touch anything and I mentioned that if I felt an earthquake I was going to run for it!
We are both really disappointed that our contractor is trying to charge us for ticky-tacky shit that we have to argue against! We didn’t think we hired the “Change Order Contractor” but it’s starting to look that way... ugh! We are already arguing about change order #3 as well.
He’s trying to charge us an extra $4,270.50 to replace our 60 year old sewer line from the front porch to the street. This scope of work was clearly requested by us in our first bid addendum that we sent the contractor a month before his final bid. In the final project budget there is even a $4,400 line item #1300 that verbatim states, “Replace Main Water Line and Sewer Line Will be going as far as we can to the city hookup.” Again we argued that he is trying to double charge us for this scope that was clearly requested in the bid documents and shown in the budget! I asked for him to tell us what the budget line item #1300 is for if it’s not the sewer and water line replacement and he tried to tell us some horseshit that it’s for replacing the sewer and water lines inside the house. I called BS on that immediately and reminded him that the plumbing scope inside the house is covered in the $21,000 line item for rough plumbing!! We are still waiting on his revised argument for why he needs to double the cost to replace the sewer line? I know we are getting all heated about this... but if he had come to us and said that he forgot to bid the excavation for the new sewer line, or that he needs a change order because the sewer line is deeper than he though we would be able to agree or meet him in the middle. I mean we are not unreasonable. But don’t lie to me that sewer replacement isn’t in your bid... you will not win that argument and instead he’s just pissing us both off! Not to mention, who the hell bids replacement of a sewer pipe and doesn’t include the cost to dig it up? If this was a commercial construction project the contractor would have to eat that cost he “forgot” to bid. How would we even know that it wasn’t included when we reviewed his bid? Brett already just wants to hire another contractor to replace our sewer line after our contractor is done so he doesn’t have to pay our contractor another dime over our budget. If the contractor keeps being a prick this might happen, but I’m not willing to burn that bridge yet... I’m still hoping that the contractor comes to his senses.
Then there’s the lovely change order #4! Apparently our contractor only bid the removal and re-sheeting of half of our roof?!?! Did he know we were planning to re-roof the whole thing... yes! Did his bid state he was planning to leave half the existing roof in place... no! BUT since we are having Brett’s Dad, who has owned his own roofing business for the past 40 years, install our new roof we agreed to the change order just because we don’t want to do the tear off ourselves. Cha-ching... extra $4,130 there... smh!
We don’t like arguing. It’s not a fun or comfortable thing to be doing with a contractor that still has 80% of the project to finish. Maybe we won the argument for change order #2 (which isn’t really a win when those structural items should never have been a change order in the first place), but now we are concerned that the contractor is going to try to make that money back on future changes or cut corners to make up the perceived “difference.” We are already 2+ weeks behind schedule and our contract doesn’t have a lot of teeth to compel our contractor to finish by a certain date. Not to mention that we still don’t even have a fucking schedule for the duration of the project! Here we are 2 months into a supposedly 6 month project and all he can give us is a 4-week look ahead... ugh! Lots of stress and frustration happening in our house these last couple weeks. Time for a drink!
1 note
·
View note
Photo
When our office manager wants to “self quarantine”, her choice is to tie her 68 pound body into a pretzel. Oh, if life was so easy....#slingshotlegalservices #mediation #construction #constructionsite #mediator #liens #collection #changeorders #foreclosure #neighborhood #dispute https://www.instagram.com/p/CAJpbltp_qf/?igshid=1ev5n45x6wf4b
#slingshotlegalservices#mediation#construction#constructionsite#mediator#liens#collection#changeorders#foreclosure#neighborhood#dispute
0 notes
Text
Chermea Construction Software to manage business strategies
Your business needs #Chermeaconstructionsoftware to manage business strategies to grow more. Book appointment, Send Customer Agreement,Send Invoice, Change Order, Issue Credit memo, and receipt manage all with our Software.
https://chermeaconstructionsoftware.com/features
0 notes
Text
@the-wip-project day 83:
Write the opening of a story with this title:
Under A Lonely Star
Ok but I'm going to do something else actually.
- - - - - - - - - - - - - - - -
It seemed like everything was going wrong that morning.
I arrived at the office a whole five minutes early for once and before I even had a chance to make it to the coffee station, chaos was already breaking out. No sooner had I sat down, I was greeted by a young, serious-looking turian.
Sam tapped his finger on my desk in an irritating gesture of greeting. "Morning," he said, setting a cluster of field notes down. "The field team just finished surveying the Nos Astra Commons, we need an updated model ASAP."
I groaned. "After coffee?"
He clicked his mandibles. "Just have it updated by lunch."
"Sure," I muttered as he padded away. I hated taking orders from the new guy. I liked it even less when it was barely 7am and my inbox was already popping off.
And just as I was getting up to fetch some coffee, my comm rang.
"Hey I'm sorry to rush you," Eleyrae said on the other line. "I'm leaving in 10 for the Dantius Towers and I need a fresh set of plans printed out."
Did you know you can print these yourself? I gagged my thoughts, rubbing my temple. "Don't you guys have a set in the field office?"
"We did. But someone broke in last night and stole them."
"Yeah right. One of the guys probably took them home."
"It's all over the news. The owner was killed in the penthouse of Tower One."
That got my attention. "And you think whoever killed the owner stole our plans??"
She hmmed on the other line, chugging the rest of her coffee. "Apparently they found so many dead mercs in the vents we're already writing up a changeorder to replace them after forensics is done."
This was going to be one of those projects that never ends.
- - - - - - - - - - - - - - - -
This is a dumb self-insert fanfic and it's been gnawing at my braincells for weeks. I'm not planning to continue it but I'm glad I got to write about Construction On an Alien Planet lmao
5 notes
·
View notes
Photo
Divine a perversely hoppy ale by @unioncraftbrewing ...Kinda Tastes like a lighter version of Change Order. I loved Change Order so this will be perfect for the spring/summer. 👍🏼🍻💄 #craftbeerreview #cbr #drinkcraft #drinklocal #divine #unioncraftbrewing #craftbeerpics #drinkbaltimore #baltimore #brewery #drinkgoodbeer #beerstagram #drinkcraftnotcorporate #craftbeerlover #cheers #hoppy #hoppy #changeorder #bmore (at Baltimore, Maryland) https://www.instagram.com/craftbeerreview/p/Bw5frBSg4O9/?utm_source=ig_tumblr_share&igshid=i3aqopvprpgw
#craftbeerreview#cbr#drinkcraft#drinklocal#divine#unioncraftbrewing#craftbeerpics#drinkbaltimore#baltimore#brewery#drinkgoodbeer#beerstagram#drinkcraftnotcorporate#craftbeerlover#cheers#hoppy#changeorder#bmore
0 notes
Photo
SAP How To Look Up Confirmation & Work Duration Through A Work Order Display! URL: https://youtu.be/KjVH0wLcVvA #iw32 #howtolookupconfirmation&workdurationthroughaworkorderdisplay #YouTube #create #changeorder #howto #sapbi #business #industrial #cmms #management #navigation #managementconsulting #sap #software #training #learning #education #sapsrm #bigdata #sapsupport #sapteched #sapscm #transaction #sapepm #control #workorder #server https://www.instagram.com/p/BulQ7ykBLMi/?utm_source=ig_tumblr_share&igshid=xomikkk7uok
#iw32#howtolookupconfirmation#youtube#create#changeorder#howto#sapbi#business#industrial#cmms#management#navigation#managementconsulting#sap#software#training#learning#education#sapsrm#bigdata#sapsupport#sapteched#sapscm#transaction#sapepm#control#workorder#server
0 notes
Text
Tbh I wish I knew more Java, cause I have a great idea for a Discord bot: roleplay manager & tracker. I know some D&D bots already exist, but they’re very much meant for D&D and only D&D. But if you have any other kind of group roleplay setting, those bots are fairly useless.
Like... I would love a bot that works like this:
A moderator can designate certain channels as RP channels.
Within one of those RP channels, users can start a thread with a simple command like !startthread.
Users can then designate themselves as active participants with !jointhread, which adds them to a reply order. They can then start typing up their replies as usual.
The bot can tell whose turn it is to reply next, and DM reminders to people if they haven’t responded in a designated amount of time.
When you’re finished with a thread, you can say !leavethread to remove yourself, and !endthread to finish it entirely.
Some other commands (which may or may not all be feasible):
!changeorder - to rearrage the turn order
!noorder - to set the thread as having no determined turn order, in which case the bot tracks if you were the last poster, and if you weren’t the last poster, how long it’s been since you posted
!skipturn - to skip your turn
!myturn - to show all threads where it’s currently your turn
!allthreads - to show all active threads and whose turn it is everywhere
!openchannels - to show which RP channels aren’t being used
!setremindtime - to change how long before the bot reminds you it’s your turn (you can say ‘never’ if you don’t want any DMs)
!hiatus - to set yourself on hiatus and disable all reply DMs (and !endhiatus to reverse it)
Some other common features from D&D bots would be nice too, such as the ability to keep track of characters and the ability to roll dice.
#personal#i took ap comp sci like... fuck it was almost six years ago now#i remember a lot of the basics but would need a TON of refreshing to attempt something like this
2 notes
·
View notes
Text
Change Order #2
Of course right when I said that we shouldn’t find any more surprises... the contractor goes and uncovers a second patio slab below the dirt that was below the larger patio slab that they already removed. Ugh!
Here’s the hidden patio slab that was found. Now you see it... $500 bucks later... now you don’t!
I should mention that we also asked them to remove all of our grass and the concrete mow curb around the border of our yard so that we could re-grade our yard. The old yard sloped to the end of our patio - since the office addition is out to the edge of our old patio, we really don’t want the yard to drain back to our house (that’s never good for the foundation). So we had them scarify the yard so we can re-grade it and have all new irrigation and drainage back there.
We thought we had clay soils... but it turns out we have pretty good dirt back there - so that’s good.
It’s like a blank slate back there now... ready for a pool? Depends on how much of our contingency is left...
Also this week they hopefully completed the abatement of our asbestos vinyl tile flooring. Here you can see they had to encapsulate the openings in the house and create a negative pressure space so that no asbestos dust escapes the house while they are scraping that crap off the slab. In the photo above you can see the vestibule they created to clean the dust off themselves as they enter and exit. I guess our original change order $$ is going to good use. Luckily our GC had plenty of work to do outside this week when he had to stay out of the inside.
Also... good bye lavender bushes, you will be missed, but I would much rather have my master bedroom and ensuite bathroom here... so I guess it’s more like, byyyeeeeeeeee!
Oh hey! Also our skylights arrived! Thanks to Velux for the $1,500 architect discount, and thanks to Matt for letting us store them securely at your house for a couple months until they are ready to be installed in February.
Next week foundation work starts for our front and back additions!!
0 notes
Photo
Just patiently waiting to go to a construction site inspection... #construction #changeorders #constructiondisputes #mediation #jobsite #disputes #conflict #conflictresolution https://www.instagram.com/p/B4s5M95nw4p/?igshid=iufn7fbglnzj
#construction#changeorders#constructiondisputes#mediation#jobsite#disputes#conflict#conflictresolution
0 notes
Text
Are There Random Numbers in CSS?
CSS allows you to create dynamic layouts and interfaces on the web, but as a language, it is static: once a value is set, it cannot be changed. The idea of randomness is off the table. Generating random numbers at runtime is the territory of JavaScript, not so much CSS. Or is it? If we factor in a little user interaction, we actually can generate some degree of randomness in CSS. Let’s take a look!
Randomization from other languages
There are ways to get some "dynamic randomization" using CSS variables as Robin Rendle explains in an article on CSS-Tricks. But these solutions are not 100% CSS, as they require JavaScript to update the CSS variable with the new random value.
We can use preprocessors such as Sass or Less to generate random values, but once the CSS code is compiled and exported, the values are fixed and the randomness is lost. As Jake Albaugh explains:
random in sass is like randomly choosing the name of a main character in a story. it's only random when written. it doesn't change.
— jake albaugh (@jake_albaugh) December 29, 2016
Why do I care about random values in CSS?
In the past, I've developed simple CSS-only apps such as a trivia game, a Simon game, and a magic trick. But I wanted to do something a little bit more complicated. I'll leave a discussion about the validity, utility, or practicality of creating these CSS-only snippets for a later time.
Based on the premise that some board games could be represented as Finite State Machines (FSM), they could be represented using HTML and CSS. So I started developing a game of Snakes and Ladders (aka Chutes and Ladders). It is a simple game. The goal is to advance a pawn from the beginning to the end of the board by avoiding the snakes and trying to go up the ladders.
The project seemed feasible, but there was something that I was missing: rolling dice!
The roll of dice (along with the flip of a coin) are universally recognized for randomization. You roll the dice or flip the coin, and you get an unknown value each time.
Simulating a random dice roll
I was going to superimpose layers with labels, and use CSS animations to "rotate" and exchange which layer was on top. Something like this:
Simulation of how the layers animate on a browser
The code to mimic this randomization is not excessively complicated and can be achieved with an animation and different animation delays:
/* The highest z-index is the numbers of sides in the dice */ @keyframes changeOrder { from { z-index: 6; } to { z-index: 1; } } /* All the labels overlap by using absolute positioning */ label { animation: changeOrder 3s infinite linear; background: #ddd; cursor: pointer; display: block; left: 1rem; padding: 1rem; position: absolute; top: 1rem; user-select: none; } /* Negative delay so all parts of the animation are in motion */ label:nth-of-type(1) { animation-delay: -0.0s; } label:nth-of-type(2) { animation-delay: -0.5s; } label:nth-of-type(3) { animation-delay: -1.0s; } label:nth-of-type(4) { animation-delay: -1.5s; } label:nth-of-type(5) { animation-delay: -2.0s; } label:nth-of-type(6) { animation-delay: -2.5s; }
The animation has been slowed down to allow easier interaction (but still fast enough to see the roadblock explained below). The pseudo-randomness is clearer, too.
See the Pen Demo of pseudo-randomly generated number with CSS by Alvaro Montoro (@alvaromontoro) on CodePen.
But then I hit a roadblock: I was getting random numbers, but sometimes, even when I was clicking on my "dice," it was not returning any value.
I tried increasing the times in the animation, and that seemed to help a bit, but I was still having some unexpected values.
That's when I did what most developers do when they find a roadblock they cannot resolve just by searching online: I asked other developers for help in the form of a StackOverflow question.
Luckily for me, the always resourceful Temani Afif came up with an explanation and a solution.
To simplify a little, the problem was that the browser only triggers the click/press event when the element that is active on mouse down is the same element that is active on mouse up.
Because of the rotating animation, the top label on mouse down was not the top label on mouse up, unless I did it fast or slow enough for the animation to circle around. That's why increasing the animation times hid these issues.
The solution was to apply a position of "static" to break the stacking context, and use a pseudo-element like ::before or ::after with a higher z-index to occupy its place. This way, the active label would always be on top when the mouse went up.
/* The active tag will be static and moved out of the window */ label:active { margin-left: 200%; position: static; } /* A pseudo-element of the label occupies all the space with a higher z-index */ label:active::before { content: ""; position: absolute; top: 0; right: 0; left: 0; bottom: 0; z-index: 10; }
Here is the code with the solution with a faster animation time:
See the Pen Demo of pseudo-randomly generated number with CSS by Alvaro Montoro (@alvaromontoro) on CodePen.
After making this change, the one thing left was to create a small interface to draw a fake dice to click, and the CSS Snakes and Ladders was completed.
This technique has some obvious inconveniences
It requires user input: a label must be clicked to trigger the "random number generation."
It doesn't scale well: it works great with small sets of values, but it is a pain for large ranges.
It’s not really random, but pseudo-random: a computer could easily detect which value would be generated in each moment.
But on the other hand, it is 100% CSS (no need for preprocessors or other external helpers) and, for a human user, it can look 100% random.
And talking about hands... This method can be used not only for random numbers but for random anything. In this case, we used it to "randomly" pick the computer choice in a Rock-Paper-Scissors game:
See the Pen CSS Rock-Paper-Scissors by Alvaro Montoro (@alvaromontoro) on CodePen.
The post Are There Random Numbers in CSS? appeared first on CSS-Tricks.
Are There Random Numbers in CSS? published first on https://deskbysnafu.tumblr.com/
0 notes
Photo
CHANGEöRDER 🔥 Imbecile / Bronx Cheer 7” 🌕 Solid debut single from this Jersey City stoner rock/noise rock outfit. There are tinges of sludge metal and grunge, and the focus is clearly on big riffs rather than feedback. The vocal delivery is a half-sung, half-yelled hybrid that lands somewhere between crooning and sneering. Limited to 100 copies on yellow vinyl with silkscreened cover and insert. 🎶🎧 Listen / Order 📦📫 http://handstandrecords.com #changeorder #imbecile #bronxcheer #jerseycity #stonerrock #noiserock #nowspinning #coloredvinyl #instavinyl (at Jersey City, New Jersey)
#jerseycity#imbecile#changeorder#noiserock#instavinyl#coloredvinyl#bronxcheer#stonerrock#nowspinning
1 note
·
View note
Photo
#CONSYSA is a cloud-based construction software that helps project managers, to track construction plans. #cloud #project #management system #Fully #integrated management tool #changeorders and #warrantyclaims unlimited users for unlimited projects https://www.consysa.com/contractor/emailtosignup
0 notes
Video
instagram
Old Masters, customers vote is in its literaly a clear choice. We will apply semigloss by stays clear #benjaminmoorepaint #staysclear #qualityeducation #drakespaint #paintsupply #changeorder (at Proficient Builders LLC) https://www.instagram.com/p/B3skf3AA_XH/?igshid=1hue1d9xqh1fy
0 notes
Text
Using NgRx for State Management in an Ionic & Angular Application
In this tutorial, we are going to tackle the basics of using NgRx for state management in an Ionic/Angular application.
If you are unfamiliar with the general concept of State Management/Redux/NgRx I would recommend watching this video: What is Redux? as a bit of a primer. The video is centered around Redux, but since NgRx is inspired by Redux the concepts are mostly the same. NgRx is basically an Angular version of Redux that makes use of RxJS and our good friends observables.
To quickly recap the main points in the Redux video, we might want to use a state management solution like NgRx/Redux because:
It provides a single source of truth for the state of your application
It behaves predictably since we only create new state through explicitly defined actions
Given the structured and centralised nature of managing state, it also creates an environment that is easier to debug
and the general concept behind these state management solutions is to:
Have a single source of “state” that is read-only
Create actions that describe some intent to change that state (e.g. adding a new note, or deleting a note)
Create reducers that take the current state and an action, and create a new state based on that (e.g. combining the current state with an action to add a new note, would return a new state that includes the new note)
To demonstrate using some pseudocode (I am just trying to highlight the basic concept here, not how you would actually do this with NgRx), we might have some “state” that looks like this:
{ notes: [ {title: 'hello'}, {title: 'there'} ], order: 'alphabetical', nightMode: false }
The data above would be our state/store that contains all of the “state” for our application. The user might want to toggle nightMode at some point, or add new notes, or change the sort order, so we would create actions to do that:
ToggleNightMode CreateNote DeleteNote ChangeOrder
An action by itself just describes intent. To actually do something with those actions we might use a reducer that looks something like this:
function reducer(state, action){ switch(action){ case ToggleNightMode: { return { // New state with night mode toggled } } default: { return // State with no changes } } }
NOTE: This is just pseudocode, do not attempt to use this in your application.
This reducer function takes in the current state, and the action, and in the case of the ToggleNightMode action being supplied it will return a new state with the nightMode property toggled.
Before We Get Started
We will be taking a look at converting a typical Ionic/Angular application to use NgRx for state management. To do that, we are going to take the application built in this tutorial: Building a Notepad Application from Scratch with Ionic and add NgRx to it. You don’t need to complete that tutorial first, but if you want to follow along step-by-step with this tutorial you should have a copy of it on your computer.
We are going to keep this as bare bones as possible and just get a basic implementation up and running - mostly we will be focusing on the ability to create notes and delete notes. My main goal with this tutorial is to help give an understanding of the basic ideas behind NgRx, and what it looks like.
There is so much you can achieve with NgRx, and you can create some very advanced/powerful implementations, but that does come with an associated level of complexity. Looking at implementations of NgRx can be quite intimidating, so I’ve tried to keep this example as basic as possible (whilst still adhering to a good general structure). In the future, we will cover more complex implementations - if there is something, in particular, you would like to see covered, let me know in the comments.
Finally, it is worth keeping in mind that solutions like NgRx and Redux are not always necessary. NgRx and Redux are both very popular (for good reason), but they are not a “standard” that everyone needs to be using in all applications. Simple applications might not necessarily realise much of a benefit through using this approach.
1. Installing NgRx
We can easily install NgRx in an existing Angular application through the ng add command:
ng add @ngrx/store
As well as installing the @ngrx/store package it will also create a reducers folder with an index.ts file that looks like this:
import { ActionReducer, ActionReducerMap, createFeatureSelector, createSelector, MetaReducer } from '@ngrx/store'; import { environment } from '../../environments/environment'; export interface State { } export const reducers: ActionReducerMap<State> = { }; export const metaReducers: MetaReducer<State>[] = !environment.production ? [] : [];
We will be adding onto this implementation throughout the tutorial, but we’re mostly just going to leave it alone for now.
One thing in particular that we haven’t covered yet, but you may notice here, is the concept of a “meta reducer”. A regular reducer is responsible for taking in the state and an action and returning a new state. A meta reducer would take in a reducer as an argument and return a new reducer (kind of like how we can pipe operators onto an observable and return an altered observable if you are familiar with that concept). We won’t be using this concept in this tutorial, but you could use a meta reducer to do things like create a logging service for debugging (e.g. create a meta reducer that logs out some value every time the ToggleNightMode action is triggered).
The ng add command also adds the following line to your app.module.ts file:
StoreModule.forRoot(reducers, { metaReducers })
This takes a global approach to implementing state management, but if you prefer you can also use StoreModule.forFeature in your individual lazy loaded modules to help keep things separate. There are many approaches you could take to structuring NgRx in your application. As I mentioned, I am trying to keep things simple here, so I would recommend taking a look at a few examples to see what style suits you best.
We are also going to store our actions in an actions folder, but the command doesn’t create that for us automatically. Let’s do that now.
Create an actions folder and note.actions.ts file at src/app/actions/note.actions.ts
Let’s start looking into how we can implement our first action.
2. Creating the Actions
To create an action we create classes that implement Action from the NgRx library. As we discussed, an action just describes intent. We won’t be adding any code to actually do anything here, we just want to describe what we want to do.
Modify src/app/actions/note.actions.ts to reflect the following:
import { Action } from "@ngrx/store"; import { Note } from "../interfaces/note"; export enum ActionTypes { CreateNote = "[Notes Service] Create note", DeleteNote = "[Notes Service] Delete note" } export class CreateNote implements Action { readonly type = ActionTypes.CreateNote; constructor(public payload: { note: Note }) {} } export class DeleteNote implements Action { readonly type = ActionTypes.DeleteNote; constructor(public payload: { note: Note }) {} } export type ActionsUnion = CreateNote | DeleteNote;
First, we have an ActionTypes enumerated type that lists our various actions related to notes, and a description of what the action will do. Since these actions will be triggered from our existing notes service (you can trigger these actions elsewhere if you like) we make a note of the source of the action in the square brackets. This is purely to be more explicit/descriptive, it doesn’t serve a functional purpose.
We then create classes for each of the actions. It implements Action, it defines a type so we can tell what kind of action it is, and we can optionally supply a payload for that action. In the case of creating and deleting notes we will need to send a payload of data to correctly add or delete a note, but some actions (like toggling nightMode) would not require a payload.
Finally, we have the ActionsUnion which exports every action created in this file.
3. Creating the Reducers
As we now know, actions don’t do anything by themselves. This is where our reducers come in. They will take the current state, and an action, and give us a new state. Let’s implement our first reducer now.
Create a file at src/app/reducers/note.reducer.ts and add the following:
import * as fromNote from "../actions/note.actions"; import { Note } from "../interfaces/note"; export interface NoteState { data: Note[]; } export const initialState: NoteState = { data: [] }; export function reducer( state = initialState, action: fromNote.ActionsUnion ): NoteState { switch (action.type) { case fromNote.ActionTypes.CreateNote: { return { ...state, data: [...state.data, action.payload.note] }; } case fromNote.ActionTypes.DeleteNote: { return { ...state, ...state.data.splice(state.data.indexOf(action.payload.note), 1) }; } default: { return state; } } }
Things are starting to look a little bit more complex now, so let’s break it down. There is some stuff we are going to need in our reducer from our note actions that we just created, so we import everything from that actions file as fromNote so that we can make use of it here (this saves us from having to import everything that we want to use from that file individually).
We define the structure or “shape” of our note state as well as supply it with an initial state:
export interface NoteState { data: Note[]; } export const initialState: NoteState = { data: [] };
The only data we are interested in are the notes themselves which will be contained under data, but we could also add additional state related to notes here if we wanted (like sort order, for example).
The last bit is the reducer function itself:
export function reducer( state = initialState, action: fromNote.ActionsUnion ): NoteState { switch (action.type) { case fromNote.ActionTypes.CreateNote: { return { ...state, data: [...state.data, action.payload.note] }; } case fromNote.ActionTypes.DeleteNote: { return { ...state, ...state.data.splice(state.data.indexOf(action.payload.note), 1) }; } default: { return state; } } }
As you can see, the arguments for the reducer function are the state and the specific action which needs to be one of all the possible note related actions which we defined in our actions file. All we are doing here is switching between the possible actions, and we handle each action differently. Although we might run different code, the goal is the same: to return the new state that we want as a result of the action.
In the case of the CreateNote action, we want to return all of the existing state, but we also want the data to contain our new note (as well as all of the existing notes). We use the spread operator ... to return a new state object containing all of the same properties and data as the existing state, except by specifying an additional data property we can overwrite the data property in the new state. To simplify that statement a bit, this:
return { ...state };
Basically means “take all of the properties out of the state object and add them to this object”. In effect, it is the same as just doing this:
return state;
Except that we are creating a new object. This:
return { ...state, data: [...state.data, action.payload.note] };
Basically means “take all of the properties out of the state object and add them to this object, except replace the data property with this new data instead”. We keep everything from the existing state, except we overwrite the data property. We do still want all of the existing notes to be in the array in addition to the new one, so we again use the spread operator (this time just on the data) to unpack all of the existing notes into a new array, and then add our new one.
To reiterate, this:
[...state.data]
would mean “create a new array and add all of the elements contained in the data array to this array” which, in effect, is the same as just using state.data directly (except that we are creating a new array with those same value). This:
[...state.data, action.payload.note]
means “create a new array and add all of the elements contained in the data array to this array, and then add action.payload.note as another element in the array. To simplify even further, let’s pretend that we are just dealing with numbers here. If state.data was the array [1, 2, 3], and action.payload.note was the number 7, then the code above would create this array:
[1, 2, 3, 7]
Hopefully that all makes sense. Once again, the role of our reducer is to modify our existing state in whatever way we want (based on the action it receives) and then return that as the new state.
Before we can make use of our actions/reducers, we need to set them up in our index.ts file.
Modify src/app/reducers/index.ts to reflect the following:
import { ActionReducer, ActionReducerMap, createFeatureSelector, createSelector, MetaReducer } from "@ngrx/store"; import { environment } from "../../environments/environment"; import * as fromNote from "./note.reducer"; export interface AppState { notes: fromNote.NoteState; } export const reducers: ActionReducerMap<AppState> = { notes: fromNote.reducer }; export const metaReducers: MetaReducer<AppState>[] = !environment.production ? [] : [];
The important part that has changed here is:
import * as fromNote from "./note.reducer"; export interface AppState { notes: fromNote.NoteState; } export const reducers: ActionReducerMap<AppState> = { notes: fromNote.reducer };
We set up our overall application state on the AppState interface (this is named State by default). We are just working with a single notes reducer here, but you could also have additional state, for example:
export interface AppState { notes: fromNote.NoteState; photos: fromPhoto.PhotoState; }
Our store or “single source of truth” creates a nested/tree structure that might look something like this:
{ notes: [ {title: 'hello'}, {title: 'there'} ], photos: [ {url: ''}, {url: ''} ] }
When we are creating our notes actions/reducers we are just working within the notes “sub-tree” but it is still a part of the entire application state tree.
We also add the reducer we created for our notes under the notes property in the reducers constant that is exported (and is in turn used in our app.module.ts by StoreModule.forRoot()).
4. Creating Selectors
The last thing we are going to do before making use of our new state management solution in our notes service is create some selectors. A selector will allow us to read state from our store.
To create a selector, we can use createSelector which is provided by NgRx. We just supply it with the state we want to select from (e.g. the “sub-tree” of our state that we want to access), and a function that returns the specific data that we are interested in.
Add the following to the bottom of src/app/reducers/note.reducer.ts:
export const getNotes = (state: NoteState) => state.data; export const getNoteById = (state: NoteState, props: { id: string }) => state.data.find(note => note.id === props.id);
We are creating two functions here to use with createSelector. The getNotes function, when given the notes from our state tree, will return just the data property (which is the one we are interested in, since it is what actually contains the notes data).
The getNoteById function will take in additional props that can be supplied when attempting to select something from the store, which will allow us to provide an id. This function will then look for a specific note in the data that matches that id and return just that note.
Add the following to the bottom of src/app/reducers/index.ts:
export const getNoteState = (state: AppState) => state.notes; export const getAllNotes = createSelector( getNoteState, fromNote.getNotes ); export const getNoteById = createSelector( getNoteState, fromNote.getNoteById );
With our functions created, we now just need to use them to create our selectors with createSelector. We first create a function called getNoteState to return the notes portion of our state tree. We then supply that, and the functions we just created, as arguments to createSelector in order to create our selector functions.
5. Accessing State and Dispatching Actions
Now everything finally comes together, and maybe you can see some of the benefit of doing all of this leg work up front. With our selectors created, we can easily get the data we want from our store wherever we like in our application. We can also easily make use of our CreateNote and DeleteNote actions.
To finish things off, we are going to keep the existing structure of the notes application, and just modify the methods in the NotesService.
Modify src/app/services.notes.service.ts to reflect the following:
import { Injectable } from "@angular/core"; import { Store } from "@ngrx/store"; import { Storage } from "@ionic/storage"; import { Observable } from "rxjs"; import { Note } from "../interfaces/note"; import * as NoteActions from "../actions/note.actions"; import { AppState, getAllNotes, getNoteById } from "../reducers"; @Injectable({ providedIn: "root" }) export class NotesService { public notes: Observable<Note[]>; constructor(private storage: Storage, private store: Store<AppState>) { this.notes = this.store.select(getAllNotes); } getNote(id: string): Observable<Note> { return this.store.select(getNoteById, { id: id }); } createNote(title): void { let id = Math.random() .toString(36) .substring(7); let note = { id: id.toString(), title: title, content: "" }; this.store.dispatch(new NoteActions.CreateNote({ note: note })); } deleteNote(note): void { this.store.dispatch(new NoteActions.DeleteNote({ note: note })); } }
To get access to our notes data, we just call this.store.select(getAllNotes) using the selector we created and it will return an observable. This observable will update any time the data in the store changes.
To get a specific note, we use our getNoteById selector, but since that selector also uses additional props (an id in this case) we pass that data along too:
return this.store.select(getNoteById, { id: id });
This will allow us to grab a specific note. Then we just have our createNote and deleteNote methods which are able to create or delete notes just be triggering the appropriate action and passing the note along with it:
this.store.dispatch(new NoteActions.CreateNote({ note: note })); this.store.dispatch(new NoteActions.DeleteNote({ note: note }));
Since we now have our notes class member set up as an observable now, if we want to be able to display the data it contains in our template we will need to add the async pipe.
Modify the <ion-item> in src/app/home/home.page.html to use the async pipe:
<ion-item button detail *ngFor="let note of (notesService.notes | async)" [routerLink]="'/notes/' + note.id" routerDirection="forward" >
The ngOnInit in the detail page will also need to be updated to make use of the observable returned by the getNote method now (if you have been following along with the notes application tutorial):
Modify ngOnInit in src/app/detail/detail.page.ts to reflect the following:
ngOnInit() { let noteId = this.route.snapshot.paramMap.get("id"); this.notesService.getNote(noteId).subscribe(note => { this.note = note; }); }
Summary
Using NgRx looks a lot more complicated than just simply managing state yourself (and it is), but like a lot of things worth doing it’s a bit more upfront work for a longer-term payoff.
The state in this example application could rather easily be managed without using an advanced state management solution like NgRx. However, as applications become more complex the upfront work in setting up NgRx can be a great investment.
via joshmorony - Learn Ionic & Build Mobile Apps with Web Tech https://ift.tt/2CNDQeA
0 notes
Text
What’s Your Workshop? How to Stay Creative & Commit to Learning New Skills
This year, you’ve resolved to work on your core design skills: Creating better ideas on your projects, improving your ability to frame problems, sketching like a pro. But the months are passing by, and you’ve barely gotten started.
It doesn’t have to be this way. For the design skills that you really want to improve this year, and beyond, create a solo workshop practice. This is where you work regularly on your own to practice and master specific skills.
You hear the word workshop used all the time in the design field, with a variety of meanings. A workshop can be a specific place you can go with the tools that you need to work on crafting things. It can be a group of artists or creators coming together to share their work and try to improve it through critique and feedback. Workshops are also convened for multidisciplinary groups to work on potential solutions to problems. These kinds of creative workshops usually have a social or collaborative component, and are geared towards improving ideas or things with the input and advice of others.
Image from Unsplash
A solo workshop practice is different. It’s a safe place to learn, to try new and different things, and to fail on your own terms. What you create is a means to an end, and doesn’t need to be completed or revised or placed in your portfolio or tweeted about. It is not social or collaborative. It is only for you.
I’ve used this approach over the years to learn a ton of skills for personal and professional means. Here’s how to set one up:
Schedule your time.
Place recurring times in your work or personal calendar to practice skills. Be realistic about how much time you’ll need to prepare to learn, practice the skills you want to learn, then reflect on what you’d learned. Depending on the skill, it’ll probably require more than an hour at a time, to start.
[Related:
Prepare to learn.
When your scheduled time arrives, go to a quiet place or environment with the materials that you need to work on a skill. Avoid distractions. Unplug from the internet, if it isn’t needed for learning, and put away any devices like your smartphone that might steal your focus.
Practice in your workshop.
Work on a particular skill for the time you’ve allocated. Make sure you’ve got breaks built in for rest, as learning takes effort. Use that rest time to jot down some things you’re discovering, not to post what you’re doing on Instagram.
Reflect & adjust for the next workshop.
Wrap your workshop up by thinking about what you want to explore in the next workshop. Based on what you’ve learned, adjust your schedule for future sessions. If you have to reschedule based on a conflict, hold yourself accountable to the learning time you’d allocated.
Sounds simple, right? Then why is it so hard for most people to get started and keep with the habit?
There are three reasons why:
Your expectations are aspirational or arbitrary.
People make commitments to aspirational or arbitrary goals, rather than figuring out what their first steps should be. When it comes to learning skills, this leads to fuzzy goals like: “I want to be better at coming up with ideas.”
The aim is pure, but the intent is too general from the start. With this example, what does “better” mean to you? How do you demonstrate “better” when practicing a design skill? Identify what it would look like behaviorally if you had put that skill into practice. Think about the learning outcomes that you want, and let them steer you. Besides, after a few weeks focusing on any new skill, you’ll be able to more accurately gauge how much time and effort it’ll take you to work your way towards a much bigger learning goal.
You’re trying to learn too many things at once.
Trying to learn or improve a skill can be complex, because mastery comes from knowing how to integrate a lot of different tasks or activities into a whole. To get better at a skill, worry less about how to put all the pieces together, and focus first on dealing with the individual pieces. And don’t get attached to those pieces of the puzzle. They’re disposable.
Your level of effort is influenced by social motivation.
Especially when developing a new skill, we look to others for support and validation that we’re going down the right path. Your friends might be clamoring to see what you’re creating. Your spouse or significant other is in the other room, and you feel the urge to show him or her your newest creation.
While it’s fine to share how you’re spending your time in your workshop, or to ask questions of others that help you better understand how to put a skill into practice, don’t share the things you are creating in your workshop with others. Any work output exists solely for you to learn from. If you start sharing what you’re creating with others, you’ll receive feedback that could influence your personal motivation to continue working on that skill.
I see these struggles firsthand at the beginning of every year, which is when a lot of designers and design thinkers get their hands on my first book, Creative Workshop: 80 Challenges to Sharpen Your Design Skills, and set a goal for themselves to publicly complete 40 to 80 challenges to take their design skills to the next level. This is an awesome goal, and I really want them to be able to do it! But the reality of completing 40 or more design challenges in a few months, let alone in a year, has proven to be overwhelming. A solo workshop approach, with a private focus on ongoing skills development and habit creation, is a better way to tackle these challenges.
In your workshop, you should be developing the ability to learn new design skills through your own motivation, separate of external pressures or feedback. As a result, you’ll be gaining personal confidence in your abilities. Then, when you want to invite others into your learning process, plan to create a separate workshop that’s intended for collaborative learning.
So, this year, what’s your workshop going to be?
David Sherwin is co-founder of Ask The Sherwins, LLC, where he coaches and advises product design teams, and develops custom training programs and tools. He is also a Fellow at frog, where he was previously an Interaction Design Director. His books from HOW include Creative Workshop and Success by Design. He writes regularly about design on his personal blog and tweets @changeorder.
Learn new design skills in these online workshops from HOW Design University:
Adobe Illustrator & Photoshop Tips & Tricks
Brush Lettering
How to Design a Digital Portfolio
The post What’s Your Workshop? How to Stay Creative & Commit to Learning New Skills appeared first on HOW Design.
What’s Your Workshop? How to Stay Creative & Commit to Learning New Skills syndicated post
0 notes